Merge branch 'R74nCom:main' into main

This commit is contained in:
OrchidtheDev 2026-02-08 12:13:53 -06:00 committed by GitHub
commit 2730c17d78
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
57 changed files with 20072 additions and 10450 deletions

View File

@ -1,10 +1,3 @@
Contributions to the main index.html file will be ignored. Use this repository to officially publish your Sandboxels mods.
This repository is no longer accepting contributions or mod submissions.
Rules for publishing mods:
1. Must not focus on something NSFW or illegal.
2. Must be tested beforehand on your own. This repo does not accept mods for the sole purpose of you testing them.
3. Must contain some meaningful content.
Failure to follow these rules may result in your pull request being ignored!
Learn more about [submitting your mod](https://sandboxels.wiki.gg/wiki/Modding/Putting_it_online).
**For future mod submissions, please go to the new repository at [R74nCom/Sandboxels-Mods](https://github.com/R74nCom/Sandboxels-Mods).**

View File

@ -8,9 +8,7 @@ Join the [Discord server](https://discord.com/invite/ejUc6YPQuS).
![Landscape made in Sandboxels](https://raw.githubusercontent.com/R74nCom/sandboxels/main/icons/cover-3840x1240px-text.png)
# Modding
New to modding? Read the Sandboxels Wiki articles on [getting started with modding](https://sandboxels.wiki.gg/wiki/Modding/Getting_started) or [publishing your mod](https://sandboxels.wiki.gg/wiki/Modding/Putting_it_online).
Please read the [Contribution Guidelines](https://github.com/R74nCom/sandboxels/tree/main/.github/CONTRIBUTING.md) before submitting your mod.
**Mods are no longer accepted in this repository.** Please go to the new one at [R74nCom/Sandboxels-Mods](https://github.com/R74nCom/Sandboxels-Mods/).
# Controls
* Left Click = Draw pixels

44
keyBindButton.js Normal file
View File

@ -0,0 +1,44 @@
async function _kBBprompt(message, defaultValue = "") {
return new Promise(resolve => {
promptInput(message, (result) => {
resolve(result);
}, "keyBindButton.js is asking you...", defaultValue);
})
}
async function _jaydalert(message) {
promptText(message, undefined, "Jayd:");
}
runAfterLoad(async () => {
window.setTimeout(async () => {
_jaydalert("Warning! keyBindButton.js is in beta, expect bugs.")
},)
})
elements.keyBindButton = {
color: "#bebfa3",
onPlace: async (pixel) => {
pixel.thisKeyIsBinded = await _kBBprompt("Select a key to bind.",(pixel.thisKeyIsBinded||undefined))
},
tick: (pixel) => {
document.onkeydown = function(kb)/*keybind*/ {
if (kb.key.toLowerCase() == pixel.thisKeyIsBinded.toLowerCase()) {
pixel.charge = 1;
}
},
document.onkeyup = function(kb)/*keybind*/ {
if (kb.key.toLowerCase() == pixel.thisKeyIsBinded.toLowerCase()) {
}
}
doDefaults(pixel);
},
perTick: () => {
mouseSize = 1;
},
ignore: ["flash"],
conduct: 1,
movable: false,
category:"machines",
darkText: true,
maxSize: 1
}

View File

@ -304,6 +304,7 @@
<tr><td>subspace.js</td><td>The Subspace Tripmine from Roblox</td><td>nousernamefound</td></tr>
<tr><td>war_crimes.js</td><td>Tear gas and more</td><td>voidapex11</td></tr>
<tr><td>weapons.js</td><td>Variety of different weapons</td><td>Jayd</td></tr>
<tr><td>weaponsRewrite.js</td><td>BETA! weapons.js is getting an overhaul, more details soon.(hopefully)</td><td>Jayd</td></tr>
<!----><tr><td class="modCat" colspan="3">Food & Cooking</td></tr><!---->
<tr><td>aChefsDream_beta.js</td><td>Beta testing for aChefsDream.js</td><td>SquareScreamYT</td></tr>
@ -376,6 +377,7 @@
<tr><td>allliquids.js</td><td>Made all elements liquids</td><td>Orchid</td></tr>
<tr><td>amogus.js</td><td>Small Among Us structure</td><td>Alice</td></tr>
<tr><td>bfdi.js</td><td>Several references to Battle for Dream Island</td><td>Taterbob</td></tr>
<tr><td>chess.js</td><td>Play chess in Sandboxels [Press U to start game]</td><td>ggod</td></tr>
<tr><td>citybuilding.js</td><td>Seeds that create miniature buildings and other city-related items</td><td>SquareScreamYT</td></tr>
<tr><td>collab_mod.js</td><td>Created by multiple people, adds random things</td><td>mrapple, ilikepizza, stefanblox</td></tr>
<tr><td>cubesstuff.js</td><td>Some random stuff like Disco Ball, Pyrite, and Nordic Gold</td><td>Cube14yt</td></tr>
@ -450,7 +452,6 @@
<tr><td>all_stain.js</td><td>Every element stains solids</td><td>stefanblox</td></tr>
<tr><td>betterMenuScreens.js</td><td>Library for mods to create their own menus</td><td>ggod</td></tr>
<tr><td>changePixelDebug.js</td><td>The changePixel() function aborts and logs to console when it tries to change to a non-existent element</td><td>Alice</td></tr>
<tr><td>changeTempReactionParameter.js</td><td>The changeTemp property to modded reactions</td><td>Alice</td></tr>
<tr><td>code_library.js</td><td>Functions and variables common to some other mods</td><td>Alice</td></tr>
<tr><td>controllable_pixel_test.js</td><td>Pixel that can be controlled with the keyboard keys <a href="https://github.com/R74nCom/sandboxels/commit/58dfa9477f2ed7ec9c44b00a35162e7c63bc129c">[More Info]</a> [PC ONLY]</td><td>Alice</td></tr>
<tr><td>customexplosion.js</td><td>Custom explosion element and interface for it</td><td>Orchid</td></tr>
@ -488,6 +489,7 @@
<tr class="deprecated"><td>advanced_colonies.js</td><td>Davlers, creatures with complex colonies</td><td>DaviStudios</td></tr>
<tr class="deprecated"><td>background_changer.js</td><td>Press 'B' to change canvas background to a URL</td><td><a href="https://R74n.com" class="R74nLink">R74n</a></td></tr>
<tr class="deprecated"><td>borders.js</td><td>Black borders around pixels (Use bright background)</td><td><a href="https://R74n.com" class="R74nLink">R74n</a></td></tr>
<tr class="deprecated"><td>changeTempReactionParameter.js</td><td>The changeTemp property to modded reactions</td><td>Alice</td></tr>
<tr class="deprecated"><td>fast_lightmap.js</td><td>Light sources glow, but faster</td><td>RedBirdly</td></tr>
<tr class="deprecated"><td>haseulite.js</td><td>Loona-related materials with various properties</td><td>Alice</td></tr>
<tr class="deprecated"><td>humans.js</td><td>Humans. Now part of the base game</td><td><a href="https://R74n.com" class="R74nLink">R74n</a></td></tr>

View File

@ -520,7 +520,7 @@ elements.RandomGen = {
elements.view_seed = {
category: "edit",
onSelect: function(){
alert(seed);
selectElement("dirt");
promptText(seed, undefined, "Seed");
selectElement(prevElement);
}
}

125
mods/Sulfuric_Dixode.js Normal file
View File

@ -0,0 +1,125 @@
if (typeof elements === "undefined") {
var elements = {};
}
if (typeof behaviors === "undefined") {
var behaviors = {};
}
if (typeof pixelMap === "undefined") {
var pixelMap = [];
}
if (typeof adjacentCoords === "undefined") {
var adjacentCoords = [
{ x: 1, y: 0 },
{ x: -1, y: 0 },
{ x: 0, y: 1 },
{ x: 0, y: -1 },
{ x: 1, y: 1 },
{ x: 1, y: -1 },
{ x: -1, y: 1 },
{ x: -1, y: -1 },
];
}
if (typeof changePixel === "undefined") {
var changePixel = function (pixel, elemName) {
pixel.element = elemName;
};
}
elements.sulfuric_acid = {
name: "Sulfuric Acid",
color: ["#c8e0ff", "#d4e8ff", "#b8d4ff"],
behavior: behaviors.LIQUID,
category: "liquids",
state: "liquid",
density: 1840,
tempHigh: 337,
stateHigh: "sulfuric_acid_gas",
tempLow: 10,
stateLow: "frozen_sulfuric_acid",
conduct: 1,
stain: 0.4,
viscosity: 0.02,
desc: "A highly corrosive, dense mineral acid. Reacts violently with water and metals.",
reactions: {
water: { elem1: "steam", elem2: "sulfuric_acid", chance: 0.6, temp1: 80 },
ice: { elem1: "water", elem2: "sulfuric_acid", chance: 0.7, temp1: 40 },
iron: { elem1: "hydrogen", elem2: "rust", chance: 0.4 },
steel: { elem1: "hydrogen", elem2: "corroded_steel", chance: 0.4 },
aluminum: { elem1: "hydrogen", elem2: "corroded_aluminum", chance: 0.4 },
wood: { elem1: "carbon", elem2: "sulfuric_acid", chance: 0.5 },
plant: { elem1: "carbon", elem2: "sulfuric_acid", chance: 0.5 },
flesh: { elem1: "carbon", elem2: "sulfuric_acid", chance: 0.5 },
},
tick: function (pixel) {
if (Math.random() < 0.05) {
var coord =
adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)];
var x = pixel.x + coord.x;
var y = pixel.y + coord.y;
if (pixelMap[x] && pixelMap[x][y]) {
var other = pixelMap[x][y];
var elemDef = elements[other.element];
if (!elemDef) {
return;
}
if (elemDef.state === "solid" && !elemDef.acid_resistant) {
if (Math.random() < 0.1) {
changePixel(other, "corroded_matter");
}
}
}
}
},
};
elements.sulfuric_acid_gas = {
name: "Sulfuric Acid Gas",
color: ["#e0f0ff", "#d0e4ff"],
behavior: behaviors.GAS,
category: "gases",
state: "gas",
density: 2,
desc: "Vaporized sulfuric acid.",
};
elements.frozen_sulfuric_acid = {
name: "Frozen Sulfuric Acid",
color: ["#9fb8e0", "#8fa8d0"],
behavior: behaviors.WALL,
category: "solids",
state: "solid",
density: 1900,
tempHigh: 10,
stateHigh: "sulfuric_acid",
desc: "Solidified sulfuric acid.",
};
elements.corroded_matter = {
name: "Corroded Matter",
color: ["#3a3a3a", "#2e2e2e", "#444444"],
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 1500,
desc: "Generic material heavily corroded by acid.",
};
elements.corroded_steel = {
name: "Corroded Steel",
color: ["#4b4b4b", "#555555", "#3f3f3f"],
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 7700,
desc: "Steel degraded by sulfuric acid.",
};
elements.corroded_aluminum = {
name: "Corroded Aluminum",
color: ["#6f6f6f", "#7a7a7a", "#656565"],
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
density: 2600,
desc: "Aluminum degraded by sulfuric acid.",
};

View File

@ -44986,7 +44986,6 @@ maxPixels (default 1000): Maximum amount of pixels/changes (if xSpacing and ySpa
function editDistance(s1, s2) {s1 = s1.toLowerCase();s2 = s2.toLowerCase();var costs = new Array();for (var i = 0; i <= s1.length; i++) {var lastValue = i;for (var j = 0; j <= s2.length; j++) {if (i == 0)costs[j] = j;else {if (j > 0) {var newValue = costs[j - 1];if (s1.charAt(i - 1) != s2.charAt(j - 1))newValue = Math.min(Math.min(newValue, lastValue),costs[j]) + 1;costs[j - 1] = lastValue;lastValue = newValue;}}}if (i > 0)costs[s2.length] = lastValue;}return costs[s2.length];}
function similarity(s1, s2) {var longer = s1;var shorter = s2;if (s1.length < s2.length) {longer = s2;shorter = s1;}var longerLength = longer.length;if (longerLength == 0) {return 1.0;}return (longerLength - editDistance(longer, shorter)) / parseFloat(longerLength);}
function mostSimilarElement(s) {
delete elements;
var max = 0;
var maxElement = "";
for (var e in elements) {

View File

@ -12,6 +12,17 @@ function findReachable(elems) {
if(e1 === "mushroom_gill") {
redo = redo || addElement_(elems, "mushroom_cap");
}
if(e1 === "oil") {
redo = redo || addElement_(elems, "lamp_oil");
redo = redo || addElement_(elems, "propane");
redo = redo || addElement_(elems, "molten_plastic");
}
if (eLists.SEEDS.includes(e1)) {
redo = redo || addElement_(elems, "fiber");
}
if(e1 === "thorium" && elems.includes("neutron")) {
@ -80,6 +91,8 @@ function findReachable(elems) {
return elems;
}
worldgentypes = {}
function addElement_(list, elem) {
if(elem instanceof Array)
{
@ -102,11 +115,11 @@ let chemMod = document.querySelector("[src=\"mods/chem.js\"]");
// unhide oxygen (air), dirt (earth), fire, and water
function loadAlchem() {
if(!elements.hematite) {
if (!elements.hematite) {
elements.hematite = {
color: ["#e0472f","#bf2a2a","#913920"],
color: ["#e0472f", "#bf2a2a", "#913920"],
behavior: behaviors.POWDER,
category: "alchemy mod",
category: "land",
density: 5250,
state: "solid",
tempHigh: 1539,
@ -114,7 +127,7 @@ function loadAlchem() {
};
elements.molten_hematite = {
reactions: {
"charcoal": { elem1: ["molten_iron","molten_iron","molten_iron","molten_iron","molten_nickel"], elem2: "carbon_dioxide"},
"charcoal": { elem1: ["molten_iron", "molten_iron", "molten_iron", "molten_iron", "molten_nickel"], elem2: "carbon_dioxide" },
},
};
elements.molten_slag.ignore.push("hematite");
@ -122,17 +135,17 @@ function loadAlchem() {
elements.molten_pyrite = {
reactions: {
"oxygen": { elem1: "iron", elem2: "sulfur_dioxide"},
"oxygen": { elem1: "iron", elem2: "sulfur_dioxide" },
},
};
elements.molten_slag.ignore.push("pyrite");
if(!elements.chalcopyrite) {
if (!elements.chalcopyrite) {
elements.chalcopyrite = {
color: ["#e8d7cb","#cdc0af","#726153","#8f775e","#bfaea0",],
color: ["#e8d7cb", "#cdc0af", "#726153", "#8f775e", "#bfaea0",],
behavior: behaviors.WALL,
category: "alchemy mod",
category: "land",
density: 4200,
state: "solid",
tempHigh: 950,
@ -140,17 +153,17 @@ function loadAlchem() {
};
elements.molten_chalcopyrite = {
reactions: {
"charcoal": { elem1: "molten_copper", elem2: ["molten_slag","molten_slag","sulfur_dioxide","sulfur_dioxide","sulfur_dioxide","molten_iron"]},
"charcoal": { elem1: "molten_copper", elem2: ["molten_slag", "molten_slag", "sulfur_dioxide", "sulfur_dioxide", "sulfur_dioxide", "molten_iron"] },
},
};
elements.molten_slag.ignore.push("chalcopyrite");
}
if(!elements.sphalerite) {
if (!elements.sphalerite) {
elements.sphalerite = {
color: ["#7a7a7a","#5c5c5c","#3d3d3d","#363636","#e0e0e0",],
color: ["#7a7a7a", "#5c5c5c", "#3d3d3d", "#363636", "#e0e0e0",],
behavior: behaviors.WALL,
category: "alchemy mod",
category: "land",
density: 4090,
state: "solid",
tempHigh: 1850,
@ -158,18 +171,18 @@ function loadAlchem() {
};
elements.molten_sphalerite = {
reactions: {
"charcoal": { elem1: "molten_zinc", elem2: ["sulfur_dioxide","sulfur_dioxide","sulfur_dioxide","sulfur_dioxide","sulfur_dioxide","gallium_gas"]},
"charcoal": { elem1: "molten_zinc", elem2: ["sulfur_dioxide", "sulfur_dioxide", "sulfur_dioxide", "sulfur_dioxide", "sulfur_dioxide", "gallium_gas"] },
},
};
elements.molten_slag.ignore.push("sphalerite");
}
if(!elements.cassiterite) {
if (!elements.cassiterite) {
elements.cassiterite = {
color: ["#5e5b5b","#705a4d","#826f6f","#333030","#e3d8d1"],
color: ["#5e5b5b", "#705a4d", "#826f6f", "#333030", "#e3d8d1"],
behavior: behaviors.WALL,
category: "alchemy mod",
category: "land",
density: 6950,
state: "solid",
tempHigh: 1630,
@ -177,17 +190,17 @@ function loadAlchem() {
};
elements.molten_cassiterite = {
reactions: {
"charcoal": { elem1: "molten_tin", elem2: "carbon_dioxide"},
"charcoal": { elem1: "molten_tin", elem2: "carbon_dioxide" },
},
};
elements.molten_slag.ignore.push("cassiterite");
}
if(!elements.galena) {
if (!elements.galena) {
elements.galena = {
color: ["#e6e6e6","#bdbdbd","#7a7a7a","#737373"],
color: ["#e6e6e6", "#bdbdbd", "#7a7a7a", "#737373"],
behavior: behaviors.WALL,
category: "alchemy mod",
category: "land",
density: 7600,
state: "solid",
tempHigh: 1113,
@ -195,178 +208,161 @@ function loadAlchem() {
};
elements.molten_galena = {
reactions: {
"charcoal": { elem1: "molten_lead", elem2: "sulfur_dioxide"},
"charcoal": { elem1: "molten_lead", elem2: "sulfur_dioxide" },
},
};
elements.molten_slag.ignore.push("galena");
}
let ores = Array(5).fill("molten_hematite")
.concat(Array(5).fill("molten_pyrite"))
.concat(Array(5).fill("molten_chalcopyrite"))
.concat(Array(3).fill("molten_cassiterite"))
.concat(Array(5).fill("molten_sphalerite"))
.concat(Array(3).fill("molten_galena"))
.concat(Array(2).fill("molten_rutile"))
.concat(Array(5).fill("molten_bauxite"))
.concat(Array(2).fill("molten_silver"))
.concat(Array(1).fill("molten_gold"))
.concat(Array(3).fill("molten_fluorite"))
.concat(Array(3).fill("molten_uraninite"))
.concat(Array(5).fill("molten_pyrite"))
.concat(Array(5).fill("molten_chalcopyrite"))
.concat(Array(3).fill("molten_cassiterite"))
.concat(Array(5).fill("molten_sphalerite"))
.concat(Array(3).fill("molten_galena"))
.concat(Array(2).fill("molten_rutile"))
.concat(Array(5).fill("molten_bauxite"))
.concat(Array(2).fill("molten_silver"))
.concat(Array(1).fill("molten_gold"))
.concat(Array(3).fill("molten_fluorite"))
.concat(Array(3).fill("molten_uraninite"));
elements.molten_slag.ignore.push("rutile");
elements.molten_slag.ignore.push("bauxite");
elements.molten_slag.ignore.push("silver");
elements.molten_slag.ignore.push("gold");
elements.seltzer.reactions["electric"] =
{ elem1: "water", elem2:"methane"};
elements.carbon_dioxide.reactions["electric"] =
{ elem1:"methane"};
elements.magma.reactions["magma"] =
{ elem2:ores, tempMin:2500, tempMax:3000, chance:0.0001};
elements.seltzer.reactions["electric"] =
{ elem1: "water", elem2: "methane" };
elements.carbon_dioxide.reactions["electric"] =
{ elem1: "methane" };
elements.magma.reactions["magma"] =
{ elem2: ores, tempMin: 2500, tempMax: 3000, chance: 0.0001 };
if (!settings.alchemyUnlocked) {
settings.alchemyUnlocked = {
"oxygen": true,
"dirt": true,
"fire": true,
"water": true,
};
}
if (settings.unlocked.alchemymod) {
for (var element in settings.unlocked) {
if (settings.unlocked[element]) {
settings.alchemyUnlocked[element] = true
}
if (!settings.alchemyUnlocked) {
settings.alchemyUnlocked = {
"oxygen": true,
"dirt": true,
"fire": true,
"water": true,
};
}
}
// loop through the elements object
if (elements.explosion) {
elements.explosion.category = "tools";
}
if (elements.room_temp) {
elements.room_temp.category = "tools";
}
if (elements.cook) {
elements.cook.category = "tools";
}
if (elements.incinerate) {
elements.incinerate.category = "tools";
}
for (var element in elements) {
if (elements[element].category === "tools") {
settings.alchemyUnlocked[element] = true;
}
if (settings.alchemyUnlocked[element]) {
elements[element].hidden = false;
if (elements[element].category !== "tools") { elements[element].category = "alchemy mod"; }
}
else if (elements[element].category !== "tools") {
// give the element the hidden attribute true
elements[element].hidden = true;
// set its category to "alchemy mod"
elements[element].category = "alchemy mod";
}
}
// set the unhide setting to Unlock as Discovered (2)
settings.unhide = 2;
runAfterLoad(function(){
checkUnlock = function(element) {
if (elements[element] && elements[element].hidden && !settings.alchemyUnlocked[element]) {
settings.alchemyUnlocked[element] = true;
if (settings.unhide === 2) {
createElementButton(element)
var categoryButton = document.querySelector(".categoryButton[current='true']");
var currentCategory = categoryButton.getAttribute("category");
if (currentCategory !== elements[element].category) {
document.getElementById("categoryButton-"+elements[element].category).classList.add("notify");
}
// add notify to the elementButton of the element
document.getElementById("elementButton-"+element).classList.add("notify");
if (settings.unlocked.alchemymod) {
for (var element in settings.unlocked) {
if (settings.unlocked[element]) {
settings.alchemyUnlocked[element] = true;
}
saveSettings();
}
}
})
runAfterAutogen(function(){
for (var element in elements) {
if (elements[element].category === "states") {
elements[element].category = "alchemy mod"
// loop through the elements object
if (elements.explosion) {
elements.explosion.category = "tools";
}
if (elements.room_temp) {
elements.room_temp.category = "tools";
}
if (elements.cook) {
elements.cook.category = "tools";
}
if (elements.incinerate) {
elements.incinerate.category = "tools";
}
// set the unhide setting to Unlock as Discovered (2)
settings.unhide = 2;
runAfterLoad(function () {
checkUnlock = function (element) {
if (elements[element] && elements[element].hidden && !settings.alchemyUnlocked[element]) {
settings.alchemyUnlocked[element] = true;
if (settings.unhide === 2) {
createElementButton(element);
var categoryButton = document.querySelector(".categoryButton[current='true']");
var currentCategory = categoryButton.getAttribute("category");
if (currentCategory !== elements[element].category) {
document.getElementById("categoryButton-" + elements[element].category).classList.add("notify");
}
// add notify to the elementButton of the element
document.getElementById("elementButton-" + element).classList.add("notify");
}
saveSettings();
}
};
});
window.addEventListener("load", function () {
for (var element in elements) {
if (elements[element].hidden && document.getElementById("elementButton-" + element)) {
document.getElementById("elementButton-" + element).remove();
}
}
});
function lockAll() {
for (var element in elements) {
if (elements[element].category === "tools") {
settings.alchemyUnlocked[element] = true;
}
if (settings.alchemyUnlocked[element]) {
elements[element].hidden = false;
}
else if (elements[element].category !== "tools") {
// give the element the hidden attribute true
elements[element].hidden = true;
}
if (elements[element].category !== "tools") {
if (!settings.alchemyUnlocked || Object.keys(settings.alchemyUnlocked).length < 25) {
elements[element].category = "alchemy mod";
}
}
}
}
})
window.addEventListener("load",function(){
for (var element in elements) {
if (elements[element].hidden && document.getElementById("elementButton-"+element)) {
document.getElementById("elementButton-"+element).remove()
}
}
})
/*runAfterAutogen(function(){
runAfterAutogen(() => runAfterAutogen(lockAll));
function printReachable() {
let reachable = findReachable(initialElements);
console.log(reachable.join(","));
let string = "";
for(let i in elements)
{
if(!reachable.includes(i))
{
if(string === "")
{
for (let i in elements) {
if (!reachable.includes(i)) {
if (string === "") {
string = i;
}
else
{
else {
string += "," + i;
}
}
}
console.log(string);
string = "";
for(let i = 0; i < reachable.length; i++)
{
if(!settings.alchemyUnlocked[reachable[i]])
{
if(string === "")
{
for (let i = 0; i < reachable.length; i++) {
if (!settings.alchemyUnlocked[reachable[i]]) {
if (string === "") {
string = reachable[i];
}
else
{
else {
string += "," + reachable[i];
}
}
}
console.log(string);
string = "";
for(let i in settings.alchemyUnlocked)
{
if(!reachable.includes(i) && settings.alchemyUnlocked[i] && elements[i].category !== "tools")
{
if(string === "")
{
for (let i in settings.alchemyUnlocked) {
if (!reachable.includes(i) && settings.alchemyUnlocked[i] && elements[i].category !== "tools") {
if (string === "") {
string = i;
}
else
{
else {
string += "," + i;
}
}
}
console.log(string);
});*/
}
// runAfterAutogen(() => runAfterAutogen(printReachable));
}
if (chemMod) {
if (chemMod.readyState === 'complete') {
loadAlchem();
} else {
chemMod.addEventListener("load", loadAlchem);
}
} else {
loadAlchem();
}
dependOn("chem.js", () => { return; }, true);
loadAlchem();

21
mods/allthemods.js Normal file
View File

@ -0,0 +1,21 @@
var mods_to_include = ["glow.js", "circuitcore.js", "clone_liquid.js", "colored_lightbulbs.js", "combustion.js", "conveyance.js", "coresbyp.js", "datawire.js", "drill.js", "ExtraMachines.js", "fans.js", "fine_tuned_cloner.js", "flipflop.js", "fueled_generators.js", "gameOfLife.js", "heatshield.js", "human_friendly_design.js", "industry.js", "logicgates.js", "note_block_advanced.js", "note_block.js", "nousersthings.js", "portal.js", "pullers.js", "pushers.js", "sandboxels.js", "schematics.js", "scp.js", "spouts.js", "state_voids.js", "switches.js", "thiquovite.js", "ticking_temp_stuff.js", "video.js", "waterspout.js", "WhisperingTheory.js", "wifi_draw.js", "aircrafts.js", "c_fighter_jet.js", "guided_rocket.js", "icb.js", "life_eater.js", "liquid_void.js", "meat_rockets.js", "more_breaking.js", "rays.js", "rays++.js", "scp.js", "subspace.js", "war_crimes.js", "weapons.js", "aChefsDream_beta.js", "aChefsDream.js", "aChefsDream2.js", "bananas.js", "CherrySoda.js", "community_desserts.js", "devsnacks.js", "GrapeSoda.js", "greenitemsandmore.js", "ketchup_mod.js", "lemonade.js", "morefoodsmod.js", "mossstuff.js", "mustard.js", "potato_chips.js", "sbstuff.js", "soups.js", "weAllScreamFor.js", "apioforms_pre.js", "baby.js", "bacteria_mod.js", "bananas.js", "biology.js", "cat.js", "cells.js", "children.js", "coldblooded.js", "colonies.js", "crimson.js", "dogs.js", "eklegems.js", "fairy_chain.js", "fantastic_creatures.js", "fantasy_elements.js", "fey_and_more.js", "fishin.js", "flowers_and_forests.js", "fwibblen.js", "genetics.js", "human_edit.js", "kopalstuff.js", "lizard_mod.js", "lost_souls.js", "miscible_psoup_and_birthpool.js", "mobs.js", "moretrees.js", "no_blood.js", "nocancer.js", "nocancer2.js", "nograssgrow.js", "ocean.js", "ores.js", "petal_dye.js", "plants.js", "primordial_birthpool.js", "scp.js", "spring.js", "the_ground_og.js", "toothpaste.js", "volcanic_expansion.js", "alcohol.js","alkahest.js","alkali_metal.js","bettermetalscrap.js","boiling_things.js","bouncing_balls.js","chalk.js","chem.js","grav_mudstones.js","halogen.js","liquid_mixing.js","lye.js","metals.js","mixture.js","moreliquids.js", "PRNGworldgenlib.js"
]
var mods_included = mods_to_include.map(mod => enabledMods.includes(mod));
var all_mods_included = mods_included.reduce(function(a,b) { return a && b });
if(!all_mods_included) {
// var mods_needed = mods_to_include.filter(function(modPath) { return !(enabledMods.includes(modPath)) });
mods_needed.forEach(function(modName) {
// enabledMods.splice(enabledMods.indexOf("allthemods"),0,modPath);
dependOn(modPath, ()=>{}, true)
});
// localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
// alert(`The following mods have been inserted: ${mods_needed.join(", ")}
// Reload the page for the mods to take effect.`)
}

277
mods/background_music.js Normal file
View File

@ -0,0 +1,277 @@
/*
function loadJsDelivr(url, callback) {
const script = document.createElement('script');
script.src = url;
script.onload = () => {
console.log('Loaded:', url);
if (callback) callback();
};
script.onerror = () => {
console.error('Failed to load:', url);
};
document.head.appendChild(script);
}
*/
/**
* @type {undefined | HTMLAudioElement}
*/
let currentMusic;
const PLAY = "\u25B6";
const PAUSE = "\u23F8";
/**
*
* @param {string|File} userAudio
*/
function setBackgroundMusic(userAudio) {
let audioSrc;
if (typeof userAudio === "string") {
if (!isValidAudioUrl(userAudio)) {
promptText("Invalid audio URL");
return;
}
audioSrc = new URL(userAudio).href;
} else if (userAudio instanceof File) {
if (!userAudio.type.startsWith("audio/")) {
promptText("Invalid audio file");
return;
}
audioSrc = URL.createObjectURL(userAudio);
} else {
promptText("Invalid audio input");
return;
}
if (currentMusic && currentMusic.src === audioSrc) return;
if (currentMusic) {
currentMusic.pause();
currentMusic.remove();
}
const audio = document.createElement('audio');
audio.src = audioSrc;
audio.loop = true;
audio.volume = 0.5;
audio.id = "bgm";
document.body.appendChild(audio);
currentMusic = audio;
// Only save if it's a URL, not a local file
if (typeof userAudio === "string") {
settings.bgMusic = audioSrc;
saveSettings();
}
logMessage(`Now playing: ${audioSrc}`);
return audio;
}
function isValidAudioUrl(inpurl) {
try {
const url = new URL(inpurl);
if (!['http:', 'https:'].includes(url.protocol)) return false;
return /\.(mp3|wav|ogg)$/i.test(url.pathname);
} catch {
return false;
}
}
let music_setting;
let play;
let playing = false;
dependOn("betterSettings.js", () => {
// @ts-ignore
const settings_tab = new SettingsTab("background_music.js")
// @ts-ignore
music_setting = new Setting("Background Music", "bgm", settingType.TEXT, false)
// @ts-ignore
play = new Setting("Play", "play", settingType.BOOLEAN, false)
settings_tab.registerSettings(undefined, play)
settings_tab.registerSettings(undefined, music_setting)
// @ts-ignore
settingsManager.registerTab(settings_tab)
}, true)
keybinds["KeyK"] = () => {
if (playing) {
document.getElementById('pauseButton').click()
}
}
function addCss() {
const CSS = `
.songControl {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
flex-wrap: nowrap;
align-items: center;
justify-content: center;
padding: 10px;
height: 20px;
pointer-events: none;
background-color: transparent;
border: 2px solid white;
box-shadow: 0 0 8px rgba(0,0,0,0.8);
}
.pixelArt {
image-rendering: pixelated;
image-rendering: crisp-edges;
width: 15px;
height: auto;
}
`
const style_div = document.createElement("style")
style_div.innerHTML = CSS
document.head.appendChild(style_div)
}
function createPauseButton() {
const pauseImgLink = "https://raw.githubusercontent.com/Cube14yt/assets/main/images/pause.png"
const playImgLink = "https://raw.githubusercontent.com/Cube14yt/assets/main/images/play.png"
const pauseButton = document.createElement("button");
/**
* @this {HTMLButtonElement}
*/
pauseButton.onclick = function () {
if (playing) {
this.replaceChildren()
let img = document.createElement("img")
img.src = playImgLink
img.classList.add("pixelArt")
this.appendChild(img)
playing = !playing
currentMusic?.pause();
} else {
this.replaceChildren()
let img = document.createElement("img")
img.src = pauseImgLink
img.classList.add("pixelArt")
this.appendChild(img)
playing = !playing
const url = music_setting.value;
if (!currentMusic) {
setBackgroundMusic(url);
}
currentMusic?.play()
}
}
pauseButton.replaceChildren()
let img = document.createElement("img")
img.src = playImgLink
img.classList.add("pixelArt")
pauseButton.appendChild(img)
pauseButton.style.pointerEvents = 'auto'
pauseButton.style.border = '2px solid white'
pauseButton.id = 'pauseButton'
return pauseButton
}
function createResetButton() {
const resetButton = document.createElement("button");
/**
* @this {HTMLButtonElement}
*/
resetButton.onclick = function () {
if (currentMusic) currentMusic.currentTime = 0
}
let img = document.createElement("img")
img.src = "https://raw.githubusercontent.com/Cube14yt/assets/main/images/reset.png"
img.classList.add("pixelArt")
resetButton.appendChild(img)
resetButton.style.pointerEvents = "auto"
resetButton.style.border = '2px solid white'
resetButton.id = 'resetButton'
return resetButton
}
function createVolumeButton() {
const volumeButton = document.createElement("button");
/**
* @this {HTMLButtonElement}
*/
volumeButton.onclick = function () {
promptInput("Input the new volume of the current music", (vol) => {
if (!currentMusic) return;
let newVolume = Number(vol)
if (!(newVolume >= 0 && newVolume <= 1)) return
currentMusic.volume = newVolume
})
}
let img = document.createElement("img")
img.src = "https://raw.githubusercontent.com/Cube14yt/assets/main/images/volume.png"
img.classList.add("pixelArt")
volumeButton.appendChild(img)
volumeButton.style.pointerEvents = "auto"
volumeButton.style.border = '2px solid white'
volumeButton.id = "volumeButton"
return volumeButton
}
function createInputButton() {
const inputButton = document.createElement('button')
inputButton.onclick = function () {
promptChoose("How do you want to input your song?", ["URL", "File"], (choice) => {
if (choice === "URL") {
promptInput("Give the url your song should use", (url) => {
music_setting.value = url
}, "Input URL")
} else if (choice === "File") {
const input = document.createElement('input')
input.type = "file"
input.addEventListener('change', (event) => {
// @ts-ignore
const file = event.target.files[0];
if (file) setBackgroundMusic(file)
})
input.click()
}
})
}
inputButton.textContent = "Input Song"
inputButton.style.pointerEvents = "auto"
inputButton.style.border = '2px solid white'
inputButton.id = 'inputButton'
return inputButton
}
function showSongUi() {
let songDiv = document.getElementById("songUiParent");
const canvas_div = document.getElementById("canvasDiv");
if (!canvas_div) {
requestAnimationFrame(showSongUi)
return
};
if (!songDiv) {
songDiv = document.createElement("div");
songDiv.classList.add("songControl");
songDiv.id = "songUiParent";
songDiv.appendChild(createPauseButton())
songDiv.append(createResetButton())
songDiv.append(createVolumeButton())
songDiv.append(createInputButton())
canvas_div.appendChild(songDiv);
}
console.log("UI loaded sucessfully")
}
addCss()
showSongUi()

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
var modName = "mods/boiling_things.js";
var libraryMod = "mods/code_library.js";
if(enabledMods.includes(libraryMod)) {
dependOn("code_library.js", function(){
//glass {
@ -533,8 +533,4 @@ if(enabledMods.includes(libraryMod)) {
};
});
} else {
alert(`The ${libraryMod} mod is required and has been automatically inserted (reload for this to take effect).`)
enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod)
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
};
}, true);

View File

@ -32,7 +32,7 @@ elements.change = {
tool: function(pixel) {
changePixel(pixel,changeTo,true);
},
category: "tools",
category: "edit",
desc: "Changes any pixels it is used on to a specified type.<br/>Currently replacing pixels with \"" + changeTo + "\".<br/><span onclick=changeElementPrompt() style=\"color: #ff00ff;\";>Press [;] or click here</span> to open the change prompt.",
};
@ -41,7 +41,7 @@ elements.alt_change = {
tool: function(pixel) {
pixel.element = changeTo;
},
category: "tools",
category: "edit",
desc: "Changes any pixels it is used on to a specified type, but keeping their non-element-based properties.<br/>Currently replacing pixels with \"" + changeTo + "\".<br/><span onclick=changeElementPrompt() style=\"color: #ff00ff;\";>Press [;] or click here</span> to open the change prompt.",
hidden: true,
};
@ -52,7 +52,7 @@ elements.alt_alt_change = {
pixel.element = changeTo;
pixel.color = pixelColorPick(pixel);
},
category: "tools",
category: "edit",
desc: "Changes any pixels it is used on to a specified type, but keeping their non-element-based properties except for color.<br/>Currently replacing pixels with \"" + changeTo + "\".<br/><span onclick=changeElementPrompt() style=\"color: #ff00ff;\";>Press [;] or click here</span> to open the change prompt.",
hidden: true,
};

View File

@ -1,3 +1,6 @@
// This mod has been deprecated as of 2026-01-22.
/*
function reactPixels(pixel1,pixel2) {
var r = elements[pixel1.element].reactions[pixel2.element];
if (r.setting && settings[r.setting]===0) {
@ -71,3 +74,4 @@ function reactPixels(pixel1,pixel2) {
if (r.func) { r.func(pixel1,pixel2); }
return r.elem1!==undefined || r.elem2!==undefined;
}
*/

14933
mods/chem.js

File diff suppressed because it is too large Load Diff

7877
mods/chemLegacy.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1435,7 +1435,7 @@ runAfterLoadList.push(() => {
if (!localStorage.getItem("chessjs-tutorial")) {
// "might break"
// i know damn well it will 100% break on mobile
alert("To start or restart chess board press 'u'. Might break on different resolutions and on mobile.");
promptText("To start or restart chess board press 'u'. Might break on different resolutions and on mobile.");
localStorage.setItem("chessjs-tutorial", true);
}
})

View File

@ -1,7 +1,7 @@
var modName = "mods/colonies.js";
var exoplanetMod = "mods/exoplanet.js";
// var exoplanetMod = "mods/exoplanet.js";
if(enabledMods.includes(exoplanetMod)) {
dependOn("exoplanet.js", function(){
window.addEventListener("load", () => {
document.getElementById("elementButton-base")?.remove()
@ -567,8 +567,4 @@ elements.arriving_rocket = {
cooldown: defaultCooldown
}
} else {
enabledMods.splice(enabledMods.indexOf(modName),0,exoplanetMod)
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
alert(`The ${exoplanetMod} mod is required and has been automatically inserted (reload for this to take effect).`)
};
}, true);

View File

@ -1,7 +1,7 @@
var modName = "mods/color_tools.js";
var libraryMod = "mods/code_library.js";
if(enabledMods.includes(libraryMod)) {
dependOn("code_library.js", function(){
var colorToolCounter = 0;
saturationAmount = 1;
saturationOp = "add";
@ -290,8 +290,4 @@ if(enabledMods.includes(libraryMod)) {
excludeRandom: true,
desc: "<span style='color:#FF00FF' onClick=colorToolFilterPrompt()>Click here to configure the element filter (applies to all color tools).</span>",
}
} else {
enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod)
alert(`The ${libraryMod} mod is required and has been automatically inserted (reload for this to take effect).`)
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
};
}, true);

View File

@ -1,7 +1,7 @@
/*
Use intellisense for sandboxels modding here:
to show availavle functions and show global variables
https://github.com/Cube14yt/sandboxels-types
https://github.com/R74nCom/sandboxels-types
*/
@ -619,37 +619,6 @@ elements.glow_stick_ice = {
state: "solid"
}
// Add TPS keybind
keybinds["KeyT"] = function () {
tpsPrompt()
}
function addRowWhenReady() {
const table = document.getElementById("controlsTable");
if (!table) {
// Table not ready yet, try again in 100ms
setTimeout(addRowWhenReady, 100);
return;
}
// Table exists, add the row
const rowCount = table.rows.length;
const newRow = table.insertRow(rowCount - 1);
const cell1 = newRow.insertCell(0);
const cell2 = newRow.insertCell(1);
cell1.textContent = "Change TPS";
cell2.innerHTML = "<kbd>T</kbd>";
console.log("Row added successfully!");
}
// Start the process
addRowWhenReady();
elements.randomizer = {
buttonColor: rainbowColor,
excludeRandom: true,
@ -794,32 +763,32 @@ elements.rgb_led = {
stateHigh: ["molten_glass", "molten_glass", "molten_glass", "molten_gallium"],
onSelect: () => {
promptInput("Enter red value (0-255):", function (r_inp) {
r_inp = parseInt(r_inp);
promptInput("Enter red value (0-255):", function (old_r_inp) {
let r_inp = parseInt(old_r_inp);
if (r_inp > 255 || r_inp < 0 || isNaN(r_inp)) {
logMessage("Red value is invalid, using default/last red value: " + globals.red);
} else {
globals.red = r_inp;
}
promptInput("Enter green value (0-255):", function (g_inp) {
g_inp = parseInt(g_inp);
promptInput("Enter green value (0-255):", function (old_g_inp) {
let g_inp = parseInt(old_g_inp);
if (g_inp > 255 || g_inp < 0 || isNaN(g_inp)) {
logMessage("Green value is invalid, using default/last green value: " + globals.green);
} else {
globals.green = g_inp;
}
promptInput("Enter blue value (0-255):", function (b_inp) {
b_inp = parseInt(b_inp);
promptInput("Enter blue value (0-255):", function (old_b_inp) {
let b_inp = parseInt(old_b_inp);
if (b_inp > 255 || b_inp < 0 || isNaN(b_inp)) {
logMessage("Blue value is invalid, using default/last blue value: " + globals.blue);
} else {
globals.blue = b_inp;
}
}, "Blue Value", globals.blue); // optional default input
}, "Green Value", globals.green);
}, "Red Value", globals.red);
}, "Blue Value", String(globals.blue)); // optional default input
}, "Green Value", String(globals.green));
}, "Red Value", String(globals.red));
},
onPlace: (pixel) => {
@ -1763,7 +1732,7 @@ globals.heatAmount = 2
elements.adjustable_heater = {
color: "#ff0000",
category: "deprecated",
category: "machines",
insulate: true,
behavior: behaviors.WALL,
@ -1846,7 +1815,7 @@ globals.coolAmount = 2; // adjustable step
elements.adjustable_cooler = {
color: "#0000ff",
category: "deprecated",
category: "machines",
insulate: true,
behavior: behaviors.WALL,
@ -2374,6 +2343,7 @@ elements.cacao_stem = {
// --- audio setup ---
// @ts-ignore
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
function playNote(frequency, duration = 1, type = "sine", volume = 0.1) {
@ -2738,13 +2708,18 @@ globals.rCircle = false
globals.rRGBLed = false
globals.rCustomBomb = false
dependOn("betterSettings.js", () => {
// @ts-ignore
var Reset = new SettingsTab("Reset");
// @ts-ignore
var resetCircle = new Setting("Reset circle value and radius on reset", "Reset circle", settingType.BOOLEAN, false, defaultValue = false);
// @ts-ignore
var resetRGBLed = new Setting("Reset RGB Led value on reset", "Reset RGB Led", settingType.BOOLEAN, false, defaultValue = false);
// @ts-ignore
var resetCustomBomb = new Setting("Reset Custom Bomb value on reset", "Reset Custom Bomb", settingType.BOOLEAN, false, defaultValue = false);
Reset.registerSettings("Reset", resetRGBLed)
Reset.registerSettings("Reset", resetCircle)
Reset.registerSettings("Reset", resetCustomBomb)
// @ts-ignore
settingsManager.registerTab(Reset);
runEveryTick(() => {
if (resetCircle.value == true) {
@ -3032,7 +3007,7 @@ elements.calculator = {
logMessage("Error")
return;
}
logMessage(Number(ans.toFixed(10)))
logMessage(ans.toFixed(10))
}
catch (e) {
logMessage("Invalid Characters Detected")
@ -3065,8 +3040,9 @@ elements.random_teleporter = {
} else pixel.fadeTo = "orange";
}
for (var i = 0; i < squareCoords.length; i++) {
let coord = squareCoords[i];
shuffleArray(squareCoordsShuffle)
for (var i = 0; i < squareCoordsShuffle.length; i++) {
let coord = squareCoordsShuffle[i];
let x = pixel.x + coord[0];
let y = pixel.y + coord[1];
if (!isEmpty(x, y)) {
@ -3248,56 +3224,6 @@ elements.element_line = {
}
}
function getSquareCoords(pixel) {
let x, y;
for (let i = 0; i < squareCoords.length; i++) {
let coord = squareCoords[i];
x = pixel.x + coord[0];
y = pixel.y + coord[1];
}
return { x, y }
}
function getAdjacentCoords(pixel) {
let x, y;
for (let i = 0; i < adjacentCoords.length; i++) {
x = pixel.x + adjacentCoords[i][0];
y = pixel.y + adjacentCoords[i][1];
}
return { x, y }
}
function getSquareCoordsShuffle(pixel) {
shuffleArray(squareCoordsShuffle);
let x, y;
for (var i = 0; i < squareCoordsShuffle.length; i++) {
var coord = squareCoordsShuffle[i];
x = pixel.x + coord[0];
y = pixel.y + coord[1];
}
return { x, y }
}
function getAdjacentCoordsShuffle(pixel) {
shuffleArray(adjacentCoordsShuffle)
let x, y
for (var i = 0; i < adjacentCoordsShuffle.length; i++) {
x = pixel.x + adjacentCoordsShuffle[i][0];
y = pixel.y + adjacentCoordsShuffle[i][1];
}
return { x, y }
}
function getScreenCoords() {
let coords = []
for (let x = 0; x <= width; x++) {
for (let y = 0; y <= height; y++) {
coords.push([x, y])
}
}
return coords
}
globals.replaceElem = "wood"
elements.replace_all_of_element = {
color: ["#35008a", "#000000"],
@ -3325,5 +3251,51 @@ elements.replace_all_of_element = {
}
}
/**
*
* @param {(pixel: Pixel | undefined) => void} callback
*/
function forEachPixel(callback) {
for (let x = 0; x <= width; x++) {
for (let y = 0; y <= height; y++) {
callback(pixelMap[x][y])
}
}
}
elements["🐔poolnoodle"] = {
category: "extras",
color: ["#7700ff", "#90ff90", "#ff0000", "#f700ff"],
buttonColor: rainbowColor,
behavior: behaviors.STURDYPOWDER,
density: 30,
properties: {
panic: 0,
panicTimer: 0
},
onClicked(pixel) {
pixel.panic = 1
pixel.panicTimer = 60
},
tick(pixel) {
if (Math.random() < 0.002) {
if (Math.random() <= 0.1 && (getPixel(pixel.x, pixel.y - 1) || outOfBounds(pixel.x, pixel.y + 1))) {
tryMove(pixel, pixel.x, pixel.y - 2) // 2 to coutneract gravity
}
Math.random() < 0.5
? tryMove(pixel, pixel.x + 1, pixel.y)
: tryMove(pixel, pixel.x - 1, pixel.y);
}
if (!pixel.panic) return
if (pixel.panicTimer <= 0) {
pixel.panic = 0
}
pixel.panicTimer--
if (Math.random() <= 0.1 && (getPixel(pixel.x, pixel.y - 1) || outOfBounds(pixel.x, pixel.y + 1))) {
tryMove(pixel, pixel.x, pixel.y - 2) // same as above
}
if (Math.random() <= 0.7) {
Math.random() <= 0.5 ? tryMove(pixel, pixel.x + 1, pixel.y) : tryMove(pixel, pixel.x - 1, pixel.y)
}
}
}

View File

@ -12,6 +12,6 @@ elements.delete_all_of_element = {
}
}
},
category: "tools",
category: "edit",
excludeRandom: true,
};

View File

@ -190,4 +190,18 @@ elements.spicy_water = {
};
elements.broth.reactions.spice = { color1:"#ef713f", tempMin:70, chance:0.05 };
elements.broth.reactions.spicy_water = { color1:"#ef713f", tempMin:70, chance:0.05 };
elements.meat.reactions.spicy_water = { elem2:"broth", color2:"#ef713f", tempMin:70 };
elements.meat.reactions.spicy_water = { elem2:"broth", color2:"#ef713f", tempMin:70 };
elements.nut_spread = {
color: "#7B4528",
behavior: behaviors.LIQUID,
viscosity: 200000,
tempHigh: 232,
stateHigh: ["smoke","smoke","smoke","smoke","salt"],
category: "food",
state: "liquid",
density: 1090.5,
isFood: true,
hidden: true
}
elements.nut_meat.reactions.chocolate_powder = { elem1:"nut_spread", elem2:"nut_spread" }

View File

@ -65,19 +65,19 @@
// info element
elements.drills_info = {
color: "#000000",
name: "drills.js",
category: "Mods",
behavior: behaviors.SELFDELETE,
maxSize: 1,
tool: function(pixel) {},
onSelect: function(pixel) {
let mod_info = "The drills.js mod adds different kinds of drills to a new 'drills' category.\n\nMod made by: Necrotic_Phantom. \n With help from: voidapex11."
alert(mod_info)
return
},
};
// elements.drills_info = {
// color: "#000000",
// name: "drills.js",
// category: "Mods",
// behavior: behaviors.SELFDELETE,
// maxSize: 1,
// tool: function(pixel) {},
// onSelect: function(pixel) {
// let mod_info = "The drills.js mod adds different kinds of drills to a new 'drills' category.\n\nMod made by: Necrotic_Phantom. \n With help from: voidapex11."
// alert(mod_info)
// return
// },
// };

34
mods/dry_acid.js Normal file
View File

@ -0,0 +1,34 @@
elements.dry_acid = {
name:"Anhydrous acid",
desc:"It's pretty much just acid without water in it.",
color: ["#62e36f", "#a5d9aa", "#b3c9b6"],
behavior: behaviors.POWDER,
category: "powders",
state: "solid",
reactions: {
"water": { elem1:"dry_acid", elem2:"acid", temp2:37.22},
"dirty_water": { elem1:null, elem2:"acid", temp2:37.22}
},
density: 1.522
}
if (elements.acid) {
if (!elements.acid.ignore) {
elements.acid.ignore = [];
}
elements.acid.ignore.push('dry_acid');
}
// Ensure the reactions object exists for the element
if (!elements.acid.reactions) {
elements.acid.reactions = {};
}
// Add the new reaction
elements.acid.reactions["dirty_water"] = {
elem1: "acid", // What this element turns into
elem2: "acid", // What the other element turns into
}
delete elements.acid.reactions.water
delete elements.water.reactions.acid

View File

@ -1152,7 +1152,7 @@ if(enabledMods.includes(loonaMod) && enabledMods.includes(fireMod) && enabledMod
burnTime: 600,
tempHigh: 200,
stateHigh: ["steam", "ash"],
onTryMoveInto: function(pixel,otherPixel) {
onMoveInto: function(pixel,otherPixel) {
var otherInfo = elements[otherPixel.element]
if(typeof(otherInfo.state) === "string" && otherInfo.state !== "gas") {
pixel.attached = false;

View File

@ -5,13 +5,13 @@ function tempToRGB(temp){
if (temp <= 6500){
return{
r: 255,
g: Math.max(-325.757*Math.pow(0.999581, temp)+272.879, 0),
b: Math.max(-571.403*Math.pow(0.999675, temp)+321.955, 0)
g: Math.trunc(Math.max(-325.757*Math.pow(0.999581, temp)+272.879, 0)),
b: Math.trunc(Math.max(-571.403*Math.pow(0.999675, temp)+321.955, 0))
}
} else {
return {
r: Math.max(604.879*Math.pow(0.999697, temp)+169.618, 0),
g: Math.max(719.488*Math.pow(0.999599, temp)+201.788, 0),
r: Math.trunc(Math.max(604.879*Math.pow(0.999697, temp)+169.618, 0)),
g: Math.trunc(Math.max(719.488*Math.pow(0.999599, temp)+201.788, 0)),
b: 255
}
}
@ -27,7 +27,7 @@ function oldtempToRgb(temp, pixel){
}
if (ctemp <= 0.5){
return{
r: (510*ctemp),
r: Math.trunc(510*ctemp),
g: 0,
b: 0,
opacity: (ctemp/1.3)
@ -35,8 +35,8 @@ function oldtempToRgb(temp, pixel){
} else {
return {
r: 255,
g: ((510*ctemp)-255),
b: ((280*ctemp)-140),
g: Math.trunc((510*ctemp)-255),
b: Math.trunc((280*ctemp)-140),
opacity: (ctemp/1.3)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,7 @@
var modName = "mods/life_eater.js";
var fireMod = "mods/fire_mod.js";
if(!enabledMods.includes(fireMod)) {
enabledMods.splice(enabledMods.indexOf(modName),0,fireMod);
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
alert(`The ${fireMod} mod is required and has been automatically inserted (reload for this to take effect).`);
} else {
dependOn("fire_mod.js", function() {
var lifeEaterCategories = ["life","auto creepers","food","fantastic creatures","fey","auto_fey"];
var lifeEaterBlacklist = ["life_eater_virus","life_eater_slurry","life_eater_infected_dirt"];
@ -166,4 +162,4 @@ if(!enabledMods.includes(fireMod)) {
stateHigh: elements.metal_scrap.stateHigh.concat("life_eater_virus","life_eater_virus","life_eater_virus"),
};
}
}, true);

View File

@ -1,29 +1,27 @@
function whenAvailable(names, callback) {
var interval = 10; // ms
window.setTimeout(function() {
let bool = true;
for(let i = 0; i < names.length; i++)
{
if(!window[names[i]])
{
bool = false;
}
}
if (bool) {
callback();
} else {
whenAvailable(names, callback);
}
}, interval);
}
// function whenAvailable(names, callback) {
// var interval = 10; // ms
// window.setTimeout(function() {
// let bool = true;
// for(let i = 0; i < names.length; i++)
// {
// if(!window[names[i]])
// {
// bool = false;
// }
// }
// if (bool) {
// callback();
// } else {
// whenAvailable(names, callback);
// }
// }, interval);
// }
var modName = "mods/metals.js";
var changeTempMod = "mods/changeTempReactionParameter.js";
var runAfterAutogenMod = "mods/runAfterAutogen2.js";
// var changeTempMod = "mods/changeTempReactionParameter.js";
// var runAfterAutogenMod = "mods/runAfterAutogen2.js";
var libraryMod = "mods/code_library.js";
var onTryMoveIntoMod = "mods/onTryMoveInto.js";
if(enabledMods.includes(changeTempMod) && enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(libraryMod) && enabledMods.includes(onTryMoveIntoMod)) {
whenAvailable(["runAfterAutogen"], function() {
dependOn("code_library.js", function(){
elements.iron.hardness = 0.74
//https://www.engineeringtoolbox.com/bhn-brinell-hardness-number-d_1365.html
//https://en.wikipedia.org/wiki/Hardnesses_of_the_elements_(data_page)
@ -483,7 +481,7 @@ if(enabledMods.includes(changeTempMod) && enabledMods.includes(runAfterAutogenMo
properties: {
oldColor: null,
},
onTryMoveInto: function(pixel,otherPixel) {
onMoveInto: function(pixel,otherPixel) {
neutronAbsorbency(pixel,otherPixel);
},
tick: function(pixel) {
@ -500,7 +498,7 @@ if(enabledMods.includes(changeTempMod) && enabledMods.includes(runAfterAutogenMo
density: 5803,
tempHigh: 4409,
behavior: behaviors.MOLTEN,
onTryMoveInto: function(pixel,otherPixel) {
onMoveInto: function(pixel,otherPixel) {
neutronAbsorbency(pixel,otherPixel);
},
tick: function(pixel) {
@ -512,7 +510,7 @@ if(enabledMods.includes(changeTempMod) && enabledMods.includes(runAfterAutogenMo
elements.zirconium_gas = {
density: 3, //Unknown/Unmeasured value
behavior: behaviors.GAS,
onTryMoveInto: function(pixel,otherPixel) {
onMoveInto: function(pixel,otherPixel) {
neutronAbsorbency(pixel,otherPixel);
},
tick: function(pixel) {
@ -781,11 +779,4 @@ if(enabledMods.includes(changeTempMod) && enabledMods.includes(runAfterAutogenMo
conduct: 0.35,
hardness: 0.7, //idk lol
};
});
} else {
if(!enabledMods.includes(changeTempMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,changeTempMod) };
if(!enabledMods.includes(libraryMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod) };
if(!enabledMods.includes(onTryMoveIntoMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,onTryMoveIntoMod) };
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
alert(`The "${changeTempMod}", "${runAfterAutogenMod}" and "${onTryMoveIntoMod}" mods are required; any missing mods in this list have been automatically inserted (reload for this to take effect).`);
};
},true)

360
mods/mixtureIII.js Normal file
View File

@ -0,0 +1,360 @@
function getName(elementList)
{
if(elementList.filter(function(item, pos, self) {
return self.indexOf(item) == pos;
}).length == 1)
{
return elementList[0];
}
let name = elementList.join("_") + "_mixture";
if(nameList[name])
{
name = nameList[name];
};
return name;
}
function makeColors(elementList)
{
return elementList.map((c) => elements[c].color instanceof Array ? elements[c].color : [elements[c].color]);
}
function mixture(elementList)
{
elementList.sort();
let name = getName(elementList);
if(!elements[name])
{
elements[name] = true;
let minTempHigh = Infinity;
let stateHigh = null;
let indexStateHigh = -1;
let maxTempLow = -Infinity;
let stateLow = null;
let indexStateLow = -1;
for(let i = 0; i < elementList.length; i++)
{
if(elements[elementList[i]])
{
if(typeof elements[elementList[i]].tempHigh === "number" && elements[elementList[i]].stateHigh)
{
if(elements[elementList[i]].tempHigh < minTempHigh)
{
minTempHigh = elements[elementList[i]].tempHigh;
indexStateHigh = i;
stateHigh = elements[elementList[i]].stateHigh;
}
}
if(typeof elements[elementList[i]].tempLow === "number" && elements[elementList[i]].stateLow)
{
if(elements[elementList[i]].tempLow > maxTempLow)
{
maxTempLow = elements[elementList[i]].tempLow;
indexStateLow = i;
stateLow = elements[elementList[i]].stateLow;
}
}
}
}
let elementList2 = elementList.slice();
let elementHigh = null;
if(indexStateHigh >= 0)
{
if(stateHigh instanceof Array)
{
elementHigh = [];
for(let i = 0; i < stateHigh.length; i++)
{
elementList2[indexStateHigh] = stateHigh[i];
elementHigh.push(mixture(elementList2));
}
}
else
{
elementList2[indexStateHigh] = stateHigh;
elementHigh = mixture(elementList2);
}
}
let elementList3 = elementList.slice();
let elementLow = null;
if(indexStateLow >= 0)
{
if(stateLow instanceof Array)
{
elementLow = [];
for(let i = 0; i < stateLow.length; i++)
{
elementList3[indexStateLow] = stateLow[i];
elementLow.push(mixture(elementList3));
}
}
else
{
elementList3[indexStateLow] = stateLow;
elementLow = mixture(elementList3);
}
}
if(elementHigh instanceof Array && elementHigh.length === 0)
{
minTempHigh = Infinity;
elementHigh = null;
}
if(elementLow instanceof Array && elementLow.length === 0)
{
maxTempLow = -Infinity;
elementLow = null;
}
let colors = makeColors(elementList.slice());
let colors2 = [];
let maxLength = Math.max(...(colors.map((c) => c.length)));
for(let i = 0; i < maxLength; i++)
{
let colors3 = [];
for(let j = 0; j < colors.length; j++)
{
colors3.push(toObject(colors[j][i%colors[j].length]));
}
colors2.push(averageRGB(colors3));
}
let temp = airTemp;
if(maxTempLow < airTemp && minTempHigh > airTemp)
{
}
else if(maxTempLow > -Infinity && minTempHigh < Infinity)
{
temp = (maxTempLow + minTempHigh)/2;
}
else if(maxTempLow > -Infinity)
{
temp = maxTempLow+20;
}
else if(minTempHigh < Infinity)
{
temp = Math.max(minTempHigh-20,absoluteZero);
}
let movable = elementList.some((c) => elements[c].movable || elements[c].movable === undefined);
let density = elementList.map((c) => elements[c].density ? elements[c].density : 0).reduce((a,b)=>a+b)/elementList.length;
let stain = elementList.map((c) => elements[c].stain ? elements[c].stain : 0).reduce((a,b)=>a+b)/elementList.length;
let states = elementList.map((c) => elements[c].state);
if(states.includes("gas"))
{
state = "gas";
density = 0;
}
else if(!movable)
{
state = "solid";
}
else if(states.includes("liquid"))
{
state = "liquid";
}
else
{
state = "solid";
}
addElement(name, {
color: colors2.length == 1 ? colors2[0] : colors2,
colorObject: colors2.length == 1 ? toObject(colors2[0]) :colors2.map((c) => toObject(c)),
tick: function(pixel) {
mixtureBehavior(pixel, elementList);
},
tempHigh: minTempHigh,
stateHigh: elementHigh,
tempLow: maxTempLow,
stateLow: elementLow,
temp: temp,
category: "mixture",
mixture: elementList,
movable: movable,
density: density,
state: state,
stain: stain,
reactions: {},
isGas: state === "gas"
});
for(let i in elements)
{
for(let j = 0; j < elementList.length; j++)
{
if(elements[i].reactions && elements[i].reactions[elementList[j]] !== undefined)
{
if(name === i)
{
continue;
}
elements[i].reactions[name] = {elem2: name, func: function(a,b){mixtureReact(b,a,elementList)}}
}
if(elements[elementList[j]].reactions && elements[elementList[j]].reactions[i] !== undefined)
{
if(name === i)
{
continue;
}
elements[name].reactions[i] = {elem2: i, func: function(a,b){mixtureReact(a,b,elementList)}}
}
}
}
}
return name;
}
function mixtureBehavior(pixel, elementList)
{
let prevCol = pixel.color;
let previous = pixel.element;
let elem = elementList[Math.floor(Math.random()*elementList.length)];
if (elements[elem].tick) { // Run tick function if it exists
elements[elem].tick(pixel);
}
if (pixel.del) {return}
if (elements[elem].behavior) { // Parse behavior if it exists
pixelTick(pixel,elements[elem].behavior);
}
if(pixel.element === previous)
{
pixel.color = prevCol;
}
}
function mixtureReact(pixel, pixel2, elementList)
{
elementList = elementList.slice();
shuffleArray(elementList);
let previous = pixel.element;
let prevCol = pixel.color;
let previous2 = pixel2.element;
let prevCol2 = pixel2.color;
for(let i = 0; i < elementList.length; i++)
{
let elem = elementList[i];
if(pixel.del)
{
return;
}
changePixel(pixel,elem, false);
let rr1 = false;
if (elements[elem].reactions !== undefined && elements[elem].reactions[pixel2.element] !== undefined) {
rr1 = reactPixels(pixel,pixel2);
}
if (!rr1 && elements[pixel2.element].reactions !== undefined && elements[pixel2.element].reactions[elem] !== undefined && !elements[pixel2.element].reactions[elem].oneway) {
reactPixels(pixel2,pixel);
}
if(pixel2.element === previous2)
{
pixel2.color = prevCol2;
}
if(!pixel.del && pixel.element === elem)
{
}
else if(pixel.del)
{
elementList.splice(elementList.indexOf(elem),1);
createPixel(mixture(elementList),pixel.x,pixel.y);
currentPixels[currentPixels.length-1].temp = pixel.temp;
return;
}
else
{
elementList.splice(elementList.indexOf(elem),1)
changePixel(pixel, mixture(elementList.concat([pixel.element])), false);
return;
}
if(pixel2.del)
{
return;
}
}
changePixel(pixel, previous, false);
pixel.color = prevCol;
}
nameList = [];
function toObject(color)
{
color = color.match(/\d+/g);
return {
r: parseInt(color[0]),
g: parseInt(color[1]),
b: parseInt(color[2])
};
}
function averageRGB2(colors)
{
return toObject(averageRGB(colors.map((d) => (toObject(d)))));
}
function averageRGB(rgblist) {
var r = 0;
var g = 0;
var b = 0;
for (var i = 0; i < rgblist.length; i++) {
var rgb = rgblist[i];
r += parseInt(rgb.r);
g += parseInt(rgb.g);
b += parseInt(rgb.b);
}
r = Math.floor(r/rgblist.length);
g = Math.floor(g/rgblist.length);
b = Math.floor(b/rgblist.length);
return "rgb("+r+","+g+","+b+")";
}
function blendColors(colorA, colorB, amount = 0.5) {
const [rA, gA, bA] = colorA.match(/\w\w/g).map((c) => parseInt(c, 16));
const [rB, gB, bB] = colorB.match(/\w\w/g).map((c) => parseInt(c, 16));
const r = Math.round(rA + (rB - rA) * amount).toString(16).padStart(2, '0');
const g = Math.round(gA + (gB - gA) * amount).toString(16).padStart(2, '0');
const b = Math.round(bA + (bB - bA) * amount).toString(16).padStart(2, '0');
return '#' + r + g + b;
}
elements.mixer2 = {
color: "#999999",
ignore: ["mixer2"],
category:"machines",
insulate:true,
hardness: 1,
tick: function(pixel) {
if (!isEmpty(pixel.x-1,pixel.y,true) && !isEmpty(pixel.x+1,pixel.y,true) && isEmpty(pixel.x,pixel.y+1,false))
{
if(elements.mixer2.ignore.includes(pixelMap[pixel.x-1][pixel.y].element) || elements.mixer2.ignore.includes(pixelMap[pixel.x+1][pixel.y].element))
{
return;
}
else
{
createPixel(mixture([pixelMap[pixel.x-1][pixel.y].element,pixelMap[pixel.x+1][pixel.y].element]),pixel.x,pixel.y+1);
deletePixel(pixel.x-1,pixel.y);
deletePixel(pixel.x+1,pixel.y);
}
}
doDefaults(pixel);
},
maxSize: 1
};

View File

@ -1,6 +1,7 @@
/*
A mod that adds some extra states of the art element.
(c) ACrazyPencil 2025
And thanks to the people who helped me with the code in the discord server.
(c) ACrazyPencil 2025-2026
*/
elements.powder_art = {
@ -15,12 +16,18 @@ elements.powder_art = {
canPlace: true,
customColor: true,
category: "powders",
related: ["art", "liquid_art", "gas_art", "breakable_art"],
related: ["art", "liquid_art", "gas_art", "breakable_art", "radiated_art"],
burn: false,
hardness: 1,
conduct: false,
stain: 0,
state: "powder"
state: "powder",
reactions: {
"radiation": { func:function(pixel, pixel2) {
pixel.element = "gas_art"
pixel2.element = "radiated_art"
}}
},
}
elements.liquid_art = {
@ -34,7 +41,7 @@ elements.liquid_art = {
canPlace: true,
customColor: true,
category: "liquids",
related: ["art", "powder_art", "breakable_art", "gas_art"],
related: ["art", "powder_art", "breakable_art", "gas_art", "radiated_art"],
burn: false,
hardness: 1,
conduct: false,
@ -53,7 +60,7 @@ elements.gas_art = {
canPlace: true,
customColor: true,
category: "gases",
related: ["art", "powder_art", "liquid_art", "breakable_art"],
related: ["art", "powder_art", "liquid_art", "breakable_art", "radiated_art"],
burn: false,
hardness: 1,
conduct: false,
@ -72,7 +79,7 @@ elements.breakable_art = {
canPlace: true,
customColor: true,
category: "solids",
related: ["art", "powder_art", "liquid_art"],
related: ["art", "powder_art", "liquid_art", "radiated_art", "gas_art"],
burn: false,
conduct: false,
stain: 0,
@ -83,7 +90,31 @@ elements.breakable_art = {
stateHigh: "gas_art",
breakInto: "powder_art",
breakIntoColorMultiplier: [1,1,1],
},
elements.radiated_art = {
name: "Radiated Art",
color: "#ffffff",
behavior: [
"XX|XX|XX",
"XX|RL:radiation%1|XX",
"M2|M1|M2"
],
tool: function(pixel) {
if (pixel.element === "paper") {
deletePixel(pixel.x,pixel.y)
}
},
canPlace: true,
customColor: true,
category: "powders",
related: ["art", "liquid_art", "gas_art", "breakable_art", "powder_art"],
burn: false,
hardness: 1,
conduct: false,
stain: 0,
state: "powder",
}
elements.art.related = ["powder_art", "liquid_art", "gas_art", "breakable_art"]
elements.art.related = ["powder_art", "liquid_art", "gas_art", "breakable_art", "radiated_art"]
elements.art.hardness = 1

View File

@ -1,27 +1,8 @@
function whenAvailable(names, callback) {
var interval = 10; // ms
window.setTimeout(function() {
let bool = true;
for(let i = 0; i < names.length; i++)
{
if(!window[names[i]])
{
bool = false;
}
}
if (bool) {
callback();
} else {
whenAvailable(names, callback);
}
}, interval);
}
var modName = "mods/neutronium_compressor.js";
var runAfterAutogenMod = "mods/runAfterAutogen2.js";
var libraryMod = "mods/code_library.js";
// var runAfterAutogenMod = "mods/runAfterAutogen2.js";
// var libraryMod = "mods/code_library.js";
if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(libraryMod)) {
whenAvailable(["urlParams","runAfterAutogen"], function() {
dependOn("code_library.js", function(){
var singularityColorTemplate = ["#202020", "#505050", "#b0b0b0", "#c7c7c7"];
singularityNumber = 10000;
@ -406,11 +387,5 @@ if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(libraryMod))
};
//Post-generation tasks
});
} else {
if(!enabledMods.includes(runAfterAutogenMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,runAfterAutogenMod) };
if(!enabledMods.includes(libraryMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod) };
alert(`The "${runAfterAutogenMod}" and "${libraryMod}" mods are required; any missing mods in this list have been automatically inserted (reload for this to take effect).`)
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
};
}, true);

View File

@ -1,4 +1,4 @@
elements.grass.tick = null;
delete elements.grass.tick;
elements.grass.behavior = [
["XX", "XX", "XX"],
["XX", "XX", "XX"],

View File

@ -2794,6 +2794,9 @@ elements.ray_emitter = {
pixelMap[lx][ly].rColor = pixel.color
pixelMap[lx][ly].color = pixel.color
}
if (["pointer", "flash", "explosion"].includes(pixel.rayElement)){
pixelMap[lx][ly].color = pixel.color
}
} else if (!isEmpty(lx, ly, true)){
if (pixelMap[lx][ly].element != pixel.rayElement && pixel.rayStoppedByWalls){
break;
@ -2901,7 +2904,7 @@ elements.specific_ray_emitter = {
}
},
hoverStat: function(pixel){
return (pixel.rayElement.toUpperCase() || "unset") + ", " + (pixel.rayStoppedByWalls.toString().toUpperCase() || "unset") + ", " + (pixel.specificRayStart || "unset") + ", " + (pixel.specificRayEnd || "unset") + ", " + (pixel.specificRayAngle || "unset")
return (pixel.rayElement || "unset").toUpperCase() + ", " + (pixel.rayStoppedByWalls || "unset").toString().toUpperCase() + ", " + (pixel.specificRayStart || "unset") + ", " + (pixel.specificRayEnd || "unset") + ", " + (pixel.specificRayAngle || "unset")
},
tick: function(pixel){
if (pixelTicks == pixel.start){
@ -2973,6 +2976,9 @@ elements.specific_ray_emitter = {
pixelMap[lx][ly].life = pixel.life
pixelMap[lx][ly].maxLife = pixel.life
}
if (["pointer", "flash", "explosion"].includes(pixel.rayElement)){
pixelMap[lx][ly].color = pixel.color
}
} else if (!isEmpty(lx, ly, true)){
if ((pixelMap[lx][ly].element != pixel.rayElement && pixel.rayStoppedByWalls) || pixelMap[lx][ly].element == pixel.stopAtElement){
break;

View File

@ -3,7 +3,7 @@ removeMod("pizzasstuff.js");
reload(); */
alert("THIS MOD IS NO LONGER SUPPORTED!\nThe mod 'pizzasstuff.s' and all of its contents have been moved to mossstuff.js.\nPlease install mossstuff.js to continue getting updates.");
// alert("THIS MOD IS NO LONGER SUPPORTED!\nThe mod 'pizzasstuff.s' and all of its contents have been moved to mossstuff.js.\nPlease install mossstuff.js to continue getting updates.");
elements.freeze_ray = {

View File

@ -1,8 +1,8 @@
var modName = "mods/portal.js";
var onTryMoveIntoMod = "mods/onTryMoveInto.js";
// var onTryMoveIntoMod = "mods/onTryMoveInto.js";
var libraryMod = "mods/code_library.js";
if(enabledMods.includes(onTryMoveIntoMod) && enabledMods.includes(libraryMod)) {
dependOn("code_library.js", function(){
//https://stackoverflow.com/a/60922255
if(!enabledMods.includes("mods/mobs.js")) {
headBodyObject = {
@ -17,7 +17,7 @@ if(enabledMods.includes(onTryMoveIntoMod) && enabledMods.includes(libraryMod)) {
_correspondingPortals: null,
},
insulate: true,
onTryMoveInto: function(pixel,otherPixel) {
onMoveInto: function(pixel,otherPixel) {
if(pixel._correspondingPortals == null) {
return;
};
@ -112,9 +112,8 @@ if(enabledMods.includes(onTryMoveIntoMod) && enabledMods.includes(libraryMod)) {
state: "solid",
insulate: true,
}
} else {
if(!enabledMods.includes(libraryMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod) };
if(!enabledMods.includes(onTryMoveIntoMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,onTryMoveIntoMod) };
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
alert(`The "${libraryMod}" and "${onTryMoveIntoMod}" mods are all required; any missing mods in this list have been automatically inserted (reload for this to take effect).`)
};
}, true);
// if(!enabledMods.includes(libraryMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod) };
// if(!enabledMods.includes(onTryMoveIntoMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,onTryMoveIntoMod) };
// localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
// alert(`The "${libraryMod}" and "${onTryMoveIntoMod}" mods are all required; any missing mods in this list have been automatically inserted (reload for this to take effect).`)

View File

@ -3,7 +3,7 @@ var variablesMod = "mods/prop and prompt variables.js";
var promptInputNullishes = ["null","none","","n/a"];
var eightSpaces = " ".repeat(8);
if(enabledMods.includes(variablesMod)) {
dependOn("prop and prompt variables.js", function(){
commandHelpObject = {
"set": "Sets properties for every pixel of a given type.\nUsage: set [property] [element] [value] <type>\nDon't include framing characters []<>.\nThe element can be \"all\" to set the property for every pixel.\nNote: Strings can't have spaces because spaces are the separator used in the parsing split().\nArguments in [brackets] are required and ones in <angle brackets> are optional.",
@ -1208,8 +1208,4 @@ Make sure to save your command in a file if you want to add this preset again.`
desc: "<span style='color:#FF00FF;' onClick=funniPrompt()>Click here or press Shift+1 to open the command prompt.</span>",
category:"special",
};
} else {
alert(`The ${variablesMod} mod is required and has been automatically inserted (reload for this to take effect).`)
enabledMods.splice(enabledMods.indexOf(modName),0,variablesMod)
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
};
}, true);

View File

@ -1,7 +1,7 @@
var modName = "mods/prop.js";
var variablesMod = "mods/prop and prompt variables.js";
if(enabledMods.includes(variablesMod)) {
dependOn("prop and prompt variables.js", function(){
propProperty = "element";
propValue = "sand";
propType = "string";
@ -212,7 +212,7 @@ if(enabledMods.includes(variablesMod)) {
};
pixelTempCheck(pixel);
},
category: "tools",
category: "edit",
desc: `Sets properties of pixels.<br/>Currently setting ${propProperty} to ${propValue} (${propType}).<br/><span onclick=propPrompt() style=\"color: #ff00ff;\";>Press [,] or click here</span> to open the property tool prompt.`,
};
@ -452,15 +452,11 @@ if(enabledMods.includes(variablesMod)) {
pixelTempCheck(pixel);
};
},
category: "tools",
category: "edit",
desc: `Changes properties of pixels.<br/>Currently ${numberAdjusterVerb} ${numberAdjusterValue} ${numberAdjusterPreposition} ${numberAdjusterProperty}.<br/><span onclick=numberAdjusterPrompt() style=\"color: #ff00ff;\";>Press [Shift+,] or click here</span> to open the adjuster tool prompt.`,
};
function updateNumberAdjusterDescription() {
elements.number_adjuster.desc = numberAdjusterReverseOrder ? `Changes numeric properties of pixels.<br/>Currently ${numberAdjusterVerb} ${numberAdjusterProperty} ${numberAdjusterPreposition} ${numberAdjusterValue}.<br/><span onclick=numberAdjusterPrompt() style=\"color: #ff00ff;\";>Press [Shift+,] or click here</span> to open the adjuster tool prompt.` : `Changes numeric properties of pixels.<br/>Currently ${numberAdjusterVerb} ${numberAdjusterValue} ${numberAdjusterPreposition} ${numberAdjusterProperty}.<br/><span onclick=numberAdjusterPrompt() style=\"color: #ff00ff;\";>Press [Shift+,] or click here</span> to open the adjuster tool prompt.`;
};
} else {
alert(`The ${variablesMod} mod is required and has been automatically inserted (reload for this to take effect).`)
enabledMods.splice(enabledMods.indexOf(modName),0,variablesMod)
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
};
}, true);

View File

@ -48,18 +48,18 @@ behaviors.SELFDELETE = [
pullerColour = '#e0adb6'
elements.pullersDesc = {
color: pullerColour,
name: 'pullers.js',
category: "Mods",
behavior: behaviors.SELFDELETE,
tool: function(pixel) {},
onSelect: function(pixel) {
let info1stMod = `pullers.js is a mod made by voidapex11 that adds pullers to sandboxels`
alert(info1stMod)
return
},
};
// elements.pullersDesc = {
// color: pullerColour,
// name: 'pullers.js',
// category: "Mods",
// behavior: behaviors.SELFDELETE,
// tool: function(pixel) {},
// onSelect: function(pixel) {
// let info1stMod = `pullers.js is a mod made by voidapex11 that adds pullers to sandboxels`
// alert(info1stMod)
// return
// },
// };
// for the inator reference: if you know you know
elements.immovable_inator = {

View File

@ -1,7 +1,7 @@
var modName = "mods/random_liquids.js";
var libraryMod = "mods/code_library.js";
if(enabledMods.includes(libraryMod)) {
dependOn("code_library.js", function(){
if(urlParams.get('liquidAmount') != null) { //null check
liquidAmount = urlParams.get('liquidAmount')
if(isNaN(liquidAmount) || liquidAmount === "" || liquidAmount === null) { //NaN check
@ -213,8 +213,4 @@ if(enabledMods.includes(libraryMod)) {
if(makeLiquidString == true) {
console.log(`Liquids added to liquidString (length ${liquidString.length})`)
}
} else {
alert(`The ${libraryMod} mod is required and has been automatically inserted (reload for this to take effect).`)
enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod)
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
};
}, true);

View File

@ -1,7 +1,7 @@
var modName = "mods/random_rocks.js";
var libraryMod = "mods/code_library.js";
if(enabledMods.includes(libraryMod)) {
dependOn("code_library.js", function(){
if(urlParams.get('rockAmount') != null) { //null check
rockAmount = urlParams.get('rockAmount')
if(isNaN(rockAmount) || rockAmount === "" || rockAmount === null) { //NaN check
@ -157,8 +157,4 @@ if(enabledMods.includes(libraryMod)) {
if(makeRockString == true) {
console.log(`Rocks added to rockString (length ${rockString.length})`)
}
} else {
alert(`The ${libraryMod} mod is required and has been automatically inserted (reload for this to take effect).`)
enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod)
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
};
}, true);

View File

@ -1,7 +1,7 @@
var modName = "mods/randomness.js";
var libraryMod = "mods/code_library.js";
if(enabledMods.includes(libraryMod)) {
dependOn("code_library.js", function(){
//i made some stupid things
//TPT reference
@ -723,8 +723,4 @@ if(enabledMods.includes(libraryMod)) {
}
}
});
} else {
if(!enabledMods.includes(libraryMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod) };
alert(`The "${libraryMod}" mod is required and has been automatically inserted (reload for this to take effect).`)
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
};
}, true);

View File

@ -1,28 +1,27 @@
function whenAvailable(names, callback) {
var interval = 10; // ms
window.setTimeout(function() {
let bool = true;
for(let i = 0; i < names.length; i++)
{
if(!window[names[i]])
{
bool = false;
}
}
if (bool) {
callback();
} else {
whenAvailable(names, callback);
}
}, interval);
}
// function whenAvailable(names, callback) {
// var interval = 10; // ms
// window.setTimeout(function() {
// let bool = true;
// for(let i = 0; i < names.length; i++)
// {
// if(!window[names[i]])
// {
// bool = false;
// }
// }
// if (bool) {
// callback();
// } else {
// whenAvailable(names, callback);
// }
// }, interval);
// }
var modName = "mods/rays.js";
var runAfterAutogenMod = "mods/runAfterAutogen2.js";
var libraryMod = "mods/code_library.js";
// var runAfterAutogenMod = "mods/runAfterAutogen2.js";
// var libraryMod = "mods/code_library.js";
if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(libraryMod)) {
whenAvailable(["raaLoaded","libraryLoaded"], function() {
dependOn("code_library.js", function(){
runAfterAutogen(function() {
snowAndIceCache = Object.keys(elements).filter(function(name) {
return name.endsWith("snow") || name.endsWith("ice") || name == "rime"
@ -455,10 +454,4 @@ whenAvailable(["raaLoaded","libraryLoaded"], function() {
}
}
};
});
} else {
if(!enabledMods.includes(libraryMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod) };
if(!enabledMods.includes(runAfterAutogenMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,runAfterAutogenMod) };
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
alert(`The "${runAfterAutogenMod}" and "${libraryMod}" mods are required and have been automatically inserted (reload for this to take effect).`);
};
},true);

View File

@ -49,7 +49,7 @@ elements.replace = {
changePixel(pixel,replaceTo,true);
};
},
category: "tools",
category: "edit",
desc: "Changes pixels of a specified type to another specified type.<br/>Currently replacing \"" + replaceFrom + "\" with \"" + replaceTo + "\".<br/><span onclick=replaceElementPrompt() style=\"color: #ff00ff;\";>Press [\"] or click here</span> to open the replace prompt.",
};
@ -60,7 +60,7 @@ elements.alt_replace = {
pixel.element = replaceTo;
};
},
category: "tools",
category: "edit",
desc: "Changes pixels of a specified type to another specified type, but keeping their non-element-based properties.<br/>Currently replacing \"" + replaceFrom + "\" with \"" + replaceTo + "\".<br/><span onclick=replaceElementPrompt() style=\"color: #ff00ff;\";>Press [\"] or click here</span> to open the replace prompt.",
hidden: true,
};
@ -73,7 +73,7 @@ elements.alt_alt_replace = {
pixel.color = pixelColorPick(pixel);
};
},
category: "tools",
category: "edit",
desc: "Changes pixels of a specified type to another specified type, but keeping their non-element-based properties except for color.<br/>Currently replacing \"" + replaceFrom + "\" with \"" + replaceTo + "\".<br/><span onclick=replaceElementPrompt() style=\"color: #ff00ff;\";>Press [\"] or click here</span> to open the replace prompt.",
hidden: true,
};

View File

@ -1,7 +1,7 @@
var modName = "mods/roseyiede.js";
var libraryMod = "mods/code_library.js";
if(enabledMods.includes(libraryMod)) {
dependOn("code_library.js", function(){
/*
//arbitrarily picked
binitialArrayL = ["m","n","p","t","ch","k","b","d","j","g","f","th","s","sh","h","l","r","y","w","z"] //:eggTF:
@ -356,8 +356,4 @@ if(enabledMods.includes(libraryMod)) {
density: 956,
temp: 120,
}
} else {
alert(`The ${libraryMod} mod is required and has been automatically inserted (reload for this to take effect).`)
enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod)
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
};
}, true);

View File

@ -1,74 +1,71 @@
var modName = "mods/random_rocks.js";
var onTryMoveIntoMod = "mods/onTryMoveInto.js";
var libraryMod = "mods/code_library.js";
// var onTryMoveIntoMod = "mods/onTryMoveInto.js";
// var libraryMod = "mods/code_library.js";
if(enabledMods.includes(onTryMoveIntoMod) && enabledMods.includes(libraryMod)) {
elements.solid_rock = {
color: ["#808080","#4f4f4f","#949494"],
behavior: behaviors.WALL,
reactions: {
"water": {elem1: "wet_sand", chance: 0.00035},
"salt_water": {elem1: "wet_sand", chance: 0.0005},
"sugar_water": {elem1: "wet_sand", chance: 0.0004},
"seltzer": {elem1: "wet_sand", chance: 0.0004},
"dirty_water": {elem1: "wet_sand", chance: 0.0004},
"soda": {elem1: "wet_sand", chance: 0.0004},
"lichen": {elem1: "dirt", chance: 0.0025},
"grape": {elem2: "juice", chance: 0.1, color2: "#291824"},
"root": {elem1: "sand", chance: 0.0004},
"wheat": {elem2: "flour"},
"primordial_soup": {elem1: "wet_sand", chance: 0.001}
},
onTryMoveInto: function(pixel,otherPixel) {
if(elements[otherPixel.element].category === "corruption") {
if(Math.random() < 0.05) {
changePixel(pixel,"corrupt_solid_rock");
return;
};
} else {
reactionStealer(pixel,otherPixel,"rock");
dependOn("code_library.js", function(){
elements.solid_rock = {
color: ["#808080","#4f4f4f","#949494"],
behavior: behaviors.WALL,
reactions: {
"water": {elem1: "wet_sand", chance: 0.00035},
"salt_water": {elem1: "wet_sand", chance: 0.0005},
"sugar_water": {elem1: "wet_sand", chance: 0.0004},
"seltzer": {elem1: "wet_sand", chance: 0.0004},
"dirty_water": {elem1: "wet_sand", chance: 0.0004},
"soda": {elem1: "wet_sand", chance: 0.0004},
"lichen": {elem1: "dirt", chance: 0.0025},
"grape": {elem2: "juice", chance: 0.1, color2: "#291824"},
"root": {elem1: "sand", chance: 0.0004},
"wheat": {elem2: "flour"},
"primordial_soup": {elem1: "wet_sand", chance: 0.001}
},
onMoveInto: function(pixel,otherPixel) {
if(elements[otherPixel.element].category === "corruption") {
if(Math.random() < 0.05) {
changePixel(pixel,"corrupt_solid_rock");
return;
};
},
tempHigh: 950,
stateHigh: "magma",
category: "land",
state: "solid",
density: 2600,
hardness: 0.55,
breakInto: "rock",
}
} else {
reactionStealer(pixel,otherPixel,"rock");
};
},
tempHigh: 950,
stateHigh: "magma",
category: "land",
state: "solid",
density: 2600,
hardness: 0.55,
breakInto: "rock",
}
if(enabledMods.includes("mods/fey_and_more.js")) {
elements.corrupt_solid_rock = {
color: ["#514c78","#514c78","#2a264d","#2a264d","#514c78","#514c78"],
behavior: behaviors.WALL,
tempHigh: 1200,
category: "corruption",
state: "solid",
density: 1250,
breakInto: "corrupt_rock",
tick: function(pixel) {
var randomNeighborOffset = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)];
var rfX = pixel.x+randomNeighborOffset[0];
var rfY = pixel.y+randomNeighborOffset[1];
if(!isEmpty(rfX,rfY,true)) {
var otherPixel = pixelMap[rfX][rfY];
if(otherPixel.element === "solid_rock") {
if(Math.random() < 0.05) {
changePixel(otherPixel,"corrupt_solid_rock")
};
if(enabledMods.includes("mods/fey_and_more.js")) {
elements.corrupt_solid_rock = {
color: ["#514c78","#514c78","#2a264d","#2a264d","#514c78","#514c78"],
behavior: behaviors.WALL,
tempHigh: 1200,
category: "corruption",
state: "solid",
density: 1250,
breakInto: "corrupt_rock",
tick: function(pixel) {
var randomNeighborOffset = adjacentCoords[Math.floor(Math.random() * adjacentCoords.length)];
var rfX = pixel.x+randomNeighborOffset[0];
var rfY = pixel.y+randomNeighborOffset[1];
if(!isEmpty(rfX,rfY,true)) {
var otherPixel = pixelMap[rfX][rfY];
if(otherPixel.element === "solid_rock") {
if(Math.random() < 0.05) {
changePixel(otherPixel,"corrupt_solid_rock")
};
};
},
};
runAfterLoad(function() {
elements.corrupt_solid_rock.reactions = elements.corrupt_land.reactions;
});
}
} else {
if(!enabledMods.includes(libraryMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod) };
if(!enabledMods.includes(onTryMoveIntoMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,onTryMoveIntoMod) };
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
alert(`The "${libraryMod}" and "${onTryMoveIntoMod}" mods are all required; any missing mods in this list have been automatically inserted (reload for this to take effect).`)
};
};
},
};
runAfterLoad(function() {
elements.corrupt_solid_rock.reactions = elements.corrupt_land.reactions;
});
}
},true);

View File

@ -1,8 +1,10 @@
var modName = "mods/sponge_edit.js";
var onTryMoveIntoMod = "mods/onTryMoveInto.js";
// var onTryMoveIntoMod = "mods/onTryMoveInto.js";
var libraryMod = "mods/code_library.js";
if(enabledMods.includes(onTryMoveIntoMod) && enabledMods.includes(libraryMod)) {
dependOn("code_library.js", function(){
elements.sponge.properties ??= {};
elements.sponge.properties.maxAbsorb = 250;
@ -34,7 +36,7 @@ if(enabledMods.includes(onTryMoveIntoMod) && enabledMods.includes(libraryMod)) {
};
};
elements.sponge.onTryMoveInto = function(pixel,otherPixel) {
elements.sponge.onMoveInto = function(pixel,otherPixel) {
var absorbedElements = Object.keys(pixel.absorbed);
if(absorbedElements.length == 0) {
return false;
@ -68,9 +70,4 @@ if(enabledMods.includes(onTryMoveIntoMod) && enabledMods.includes(libraryMod)) {
};
};
};
} else {
enabledMods.splice(enabledMods.indexOf(modName),0,onTryMoveIntoMod);
enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod);
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
alert(`The ${onTryMoveIntoMod} mod and ${libraryMod} mods are required and have been automatically inserted (reload for this to take effect).`);
};
}, true);

View File

@ -1,7 +1,7 @@
var modName = "mods/color_tools.js";
var libraryMod = "mods/code_library.js";
if(enabledMods.includes(libraryMod)) {
dependOn("code_library.js", function(){
stripeFixedDefaultProperties = {
color2: "rgb(0,0,0)",
phase: 0,
@ -103,8 +103,4 @@ if(enabledMods.includes(libraryMod)) {
},
desc: stripePaintDesc
};
} else {
alert(`The ${libraryMod} mod is required and has been automatically inserted (reload for this to take effect).`)
enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod)
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
};
}, true);

View File

@ -1,10 +1,7 @@
var modName = "mods/structure_test.js";
var libraryMod = "mods/code_library.js";
if(!enabledMods.includes(libraryMod)) {
enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod);
alert(`The ${libraryMod} mod is required and has been automatically inserted (reload for this to take effect).`);
} else {
dependOn("code_library.js", function(){
arrayLoaderVoids = ["air", "null", null];
buildingOneSegmentDoor = ["concrete","wood_plank","concrete","wood_plank","concrete"];
buildingOneSegmentWindows = ["concrete","glass_pane","concrete","glass_pane","concrete"];
@ -752,4 +749,4 @@ if(!enabledMods.includes(libraryMod)) {
worldgentypes.desert.layers.shift();
};
};
};
}, true);

View File

@ -76,13 +76,19 @@ runAfterAutogen(function(){
for (var element in elements) {
if (elements[element].category !== "tools") {
elements[element].hidden = true;
elements[element].category = "inventory";
if (!settings.survival || Object.keys(settings.survival).length < 25) {
elements[element].category = "inventory";
}
}
if (elements[element].onShiftSelect) delete elements[element].onShiftSelect;
}
for (var element in settings.survival) {
if (!elements[element]) { continue; }
if (elements[element].category === "tools") { continue; }
if (!elements[element].colorObject) {
elements[element].color = "#ffffff";
elements[element].colorObject = {"r": 255,"g": 255,"b": 255};
}
createElementButton(element);
document.getElementById("elementButton-"+element).innerHTML += "("+settings.survival[element]+")";
}
@ -120,7 +126,7 @@ elements.cloner.ignore = elements.cloner.ignore.concat(["gold","gold_coin","molt
elements.cloner.desc = "You can only clone one element at a time!"
elements.smash.tool = function(pixel) {
if (elements[pixel.element].seed === true && pixel.element !== "cactus") { return }
if (elements[pixel.element].seed === true) { return }
if (elements[pixel.element].breakInto !== undefined || (elements[pixel.element].seed !== undefined && elements[pixel.element].seed !== true)) {
// times 0.25 if not shiftDown else 1
if (Math.random() < (elements[pixel.element].hardness || 1) * (shiftDown ? 1 : 0.25)) {

View File

@ -1,7 +1,7 @@
var modName = "mods/wifi.js";
var libraryMod = "mods/code_library.js";
if(enabledMods.includes(libraryMod)) {
dependOn("code_library.js", function(){
//https://stackoverflow.com/a/60922255
elements.wifi = {
color: "#bfff7f",
@ -155,8 +155,4 @@ if(enabledMods.includes(libraryMod)) {
state: "solid",
}
} else {
if(!enabledMods.includes(libraryMod)) { enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod) };
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
alert(`The "${libraryMod}" mods is required; and has been automatically inserted (reload for this to take effect).`)
};
}, true);

View File

@ -1,7 +1,7 @@
var modName = "mods/wirelike_test.js";
var libraryMod = "mods/code_library.js";
if(enabledMods.includes(libraryMod)) {
dependOn("code_library.js", function(){
//The CMYK is symbolic
elements.start_test = {
color: "#dddddd",
@ -674,8 +674,4 @@ if(enabledMods.includes(libraryMod)) {
};
},
};
} else {
alert(`The ${libraryMod} mod is required and has been automatically inserted (reload for this to take effect).`)
enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod)
localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
};
}, true)

File diff suppressed because it is too large Load Diff

View File

@ -1,322 +1,606 @@
const zoom_levels = [
0.5,
1,
2,
3,
6,
12
]
window.zoom_data_div = null
window.zoom_level = 1
window.zoom_panning = [0,0]
let colour_setting;
dependOn("betterSettings.js", () => {
const settings_tab = new SettingsTab("zoom.js");
colour_setting = new Setting(
"Canvas background",
"canvas_bkg",
settingType.COLOR,
false,
defaultValue="#252525"
);
settings_tab.registerSettings(undefined, colour_setting)
settingsManager.registerTab(settings_tab)
})
function handle_zoom(direction){
switch (direction){
case "in":
if (!(zoom_level+1 in zoom_levels)) { break; }
window.zoom_level += 1
break;
case "out":
if (!(zoom_level-1 in zoom_levels)) { break; }
window.zoom_level -= 1
break;
}
rescale()
}
function handle_pan(direction, speed){
switch (direction){
case "right":
zoom_panning[0] -= speed
break;
case "left":
zoom_panning[0] += speed
break;
case "up":
zoom_panning[1] += speed
break;
case "down":
zoom_panning[1] -= speed
break;
}
rescale()
}
function gen_button(row, col, html, click, nopos, id){
const elem = document.createElement("button")
if (!nopos){
elem.style.gridColumn = row
elem.style.gridRow = col
// zoom.js
"use strict";
(() => {
// src/custom_setting_types.ts
var def_classes = () => {
class Numlist2 extends Setting {
step;
input_container = null;
push_btn = null;
pop_btn = null;
constructor(name, storage_name, desc, options) {
super(
name,
storage_name,
[5, 0],
options.disabled,
options.default_values,
desc,
options.custom_validator
);
this.step = options.step ?? 1;
}
#new_input(value, i) {
const elem = document.createElement("input");
elem.type = "number";
elem.value = value.toString();
elem.step = this.step.toString();
elem.onchange = (ev) => {
const parsed = Number.parseFloat(ev.target.value);
if (!Number.isNaN(parsed)) {
this.value[i] = parsed;
this.set(this.value);
}
};
return elem;
}
#push_pop_btns() {
this.push_btn = document.createElement("button");
this.push_btn.style.color = "#0F0";
this.push_btn.innerText = "+";
this.pop_btn = document.createElement("button");
this.pop_btn.style.color = "#F00";
this.pop_btn.innerText = "-";
this.push_btn.onclick = () => {
this.value.push(1);
this.input_container.append(this.#new_input(1, this.value.length));
};
this.pop_btn.onclick = () => {
this.value.pop();
if (this.input_container.lastChild) {
this.input_container.removeChild(this.input_container.lastChild);
}
};
return [this.push_btn, this.pop_btn];
}
disable() {
this.push_btn?.setAttribute("disabled", "true");
this.pop_btn?.setAttribute("disabled", "true");
}
enable() {
this.push_btn?.removeAttribute("disabled");
this.pop_btn?.removeAttribute("disabled");
}
build() {
const value = this.get();
const container = document.createElement("span");
container.classList.add("setting-span", "zm_nml_setting");
const l_container = document.createElement("span");
const label = document.createElement("span");
label.innerText = this.name;
const btn_container = document.createElement("span");
btn_container.classList.add("zm_nml_btn_container");
btn_container.append(...this.#push_pop_btns());
l_container.append(label, document.createElement("br"), btn_container);
this.input_container = document.createElement("span");
this.input_container.classList.add("zm_nml_icontainer");
const elems = [];
value.forEach((x, i) => {
elems.push(this.#new_input(x, i));
});
this.input_container.append(...elems);
container.append(l_container, this.input_container);
return container;
}
}
if (id) { elem.id = id }
// Table for the data-pos to assign (row major). If null, don't add.
const data_pos_map = [
["tl", null, "tr"],
[null, null, null],
["bl", null, "br"]
]
elem.innerHTML = html
elem.onclick = click
if (data_pos_map[row-1][col-1] !== null) {
elem.dataset.pos = data_pos_map[row-1][col-1]
class MultiSetting extends Setting {
settings;
elements = [];
multi_input_name;
rows = [];
constructor(name, storage_name, extra_opts, ...settings) {
super(
name,
storage_name,
[255],
extra_opts.disabled,
extra_opts.default_value ?? 0,
extra_opts.desc,
void 0
);
this.settings = settings;
this.multi_input_name = crypto.randomUUID();
}
build() {
const container = document.createElement("span");
this.settings.forEach((setting, i) => {
const row_container = document.createElement("div");
row_container.classList.add("zm_ms_row");
this.rows.push(row_container);
const select_btn = document.createElement("button");
select_btn.classList.add("zm_ms_selbtn");
select_btn.innerText = "#";
const built_item = setting.build();
built_item.classList.add("zm_ms_item");
built_item.dataset.index = i.toString();
row_container.dataset.current = i == this.value ? "true" : "false";
select_btn.onclick = () => {
this.set(i);
setting.enable();
for (const setting2 of this.settings) setting2.disable();
for (const row of this.rows) {
row.dataset.current = "false";
row.querySelectorAll(".zm_ms_item input").forEach((x) => x.setAttribute("disabled", "true"));
}
built_item.querySelectorAll("input").forEach((x) => x.removeAttribute("disabled"));
row_container.dataset.current = "true";
};
row_container.append(select_btn, built_item);
container.appendChild(row_container);
});
return container;
}
}
return elem
}
function add_css(){
const CSS = `
#zm_data_div { margin-bottom: 10px }
#canvasDiv { overflow: hidden; background-color: var(--opac-85) }
@media(pointer=coarse){
#zm_floater_container#zm_floater_container {
width: 40%;
height: auto;
class SettingGroup extends Setting {
settings;
constructor(settings) {
super(
"",
"",
[2763],
false
);
this.settings = settings;
}
enable() {
for (const x of Object.values(this.settings)) {
x.enable();
}
#zm_floater_container:has(#zm_collapse[data-collapsed="true"]){
width: calc(40% / 3);
}
disable() {
for (const x of Object.values(this.settings)) {
x.disable();
}
}
@media(pointer:coarse) and (orientation:landscape){
#zm_floater_container#zm_floater_container {
width: auto;
top: 5px;
}
#zm_floater_container:has(#zm_collapse[data-collapsed="true"]){
width: calc(40% / 3);
}
build() {
const container = document.createElement("div");
for (const x of Object.values(this.settings)) {
container.appendChild(x.build());
}
return container;
}
get() {
return this.settings;
}
// Override these so the defaults don't do anything
set() {
}
update() {
}
onUpdate() {
}
}
return {
Numlist: Numlist2,
MultiSetting,
SettingGroup
};
};
#colorSelector { z-index: 1; right: 5px }
#zm_floater_container {
position: absolute;
display: grid;
right: 5px;
bottom: 5px;
height: 100px;
aspect-ratio: 1;
max-width: 200px;
max-height: 200px;
border: 2px solid white;
background-color: black;
font-size: 120%;
button { text-align: center; border: 0px solid white }
button:where([data-pos="tl"]) { border-width: 0px 2px 2px 0px };
button:where([data-pos="tr"]) { border-width: 2px 2px 0px 0px };
button:where([data-pos="bl"]) { border-width: 0px 0px 2px 2px };
button:where([data-pos="br"]) { border-width: 2px 0px 0px 2px };
}
#zm_floater_container:has(#zm_collapse[data-collapsed="true"]) {
height: 50px;
button:not(#zm_collapse) {
display: none;
}
}
#canvasDiv:has(#colorSelector[style *= "block"]) #zm_floater_container {
bottom: 50px;
}
.zm_corner { border: 2px solid white; }
#zm_collapse {
grid-row: 3;
grid-column: 3;
}
#zm_collapse[data-collapsed="true"] {
grid-row: 1;
grid-column: 1;
border-width: 0px;
}
`
const style_div = document.createElement("style")
style_div.innerHTML = CSS
document.head.appendChild(style_div)
}
function add_zoom_floaters(){
const container = document.createElement("div")
container.id = "zm_floater_container"
// Pan mode selector (C: Coarse F: Fine)
const pan_mode_sel = gen_button(
1,3, "C",
(evt) => {
evt.target.dataset.mode = evt.target.dataset.mode == "F" ? "C" : "F"
evt.target.innerText = evt.target.dataset.mode
},
// src/custom_settings.ts
var CustomSettingsManager = class {
canvas_bkg;
zoom;
unl_zoom;
fpan_speed;
cpan_speed;
upan_speed;
use_ijkl;
show_floater;
pan_zeroing_en;
zoom_zeroing_en;
constructor(on_edit) {
const { Numlist: Numlist2, MultiSetting, SettingGroup } = def_classes();
const settings_tab = new SettingsTab("zoom.js");
const validator = () => {
on_edit.cb(this);
return true;
};
this.canvas_bkg = new Setting(
"Canvas background",
"canvas_bkg",
settingType.COLOR,
false,
"zm_panmode_sel"
)
const speed = () =>
(window.zoom_level > 3 ? 5 : 10) * // More granular at higher zoom levels
(pan_mode_sel.dataset.mode == "F" ? 0.25 : 1) // Increase granularity in fine mode
container.append(
// Direction buttons
gen_button(2,1, "&uarr;", () => handle_pan("up" ,speed())),
gen_button(1,2, "&larr;", () => handle_pan("left" ,speed())),
gen_button(3,2, "&rarr;", () => handle_pan("right" ,speed())),
gen_button(2,3, "&darr;", () => handle_pan("down" ,speed())),
// Zoom buttons
gen_button(1,1, "+", () => handle_zoom("in")),
gen_button(3,1, "-", () => handle_zoom("out")),
// Collapse button
gen_button(
3,3, "#",
(evt) => {
evt.target.dataset.collapsed = evt.target.dataset.collapsed == "true"
? "false"
: "true"
},
true,
"zm_collapse"
"#252525",
"The colour for the area around the canvas",
validator
);
this.cpan_speed = new Setting(
"Coarse pan speed",
"cpan_speed",
settingType.NUMBER,
false,
10,
"The default pan speed",
validator
);
this.fpan_speed = new Setting(
"Fine pan speed",
"fpan_speed",
settingType.NUMBER,
false,
3,
"The pan speed when holding shift (F in the floater)",
validator
);
this.upan_speed = new Setting(
"Ultrafine pan speed",
"upan_speed",
settingType.NUMBER,
false,
1,
"The pan speed when holding alt (U in the floater)",
validator
);
this.show_floater = new Setting(
"Show floater",
"show_floater",
settingType.BOOLEAN,
false,
true,
"Whether to show the floater or not",
validator
);
this.use_ijkl = new Setting(
"Use IJKL",
"use_ijkl",
settingType.BOOLEAN,
false,
false,
"Makes the mod use IJKL instead of WASD for panning (requires refresh)",
validator
);
this.pan_zeroing_en = new Setting(
"Enable pan zeroing",
"en_pzero",
settingType.BOOLEAN,
false,
true,
"Allows the Q key to reset pan (requires refresh)",
validator
);
this.zoom_zeroing_en = new Setting(
"Enable zoom zeroing",
"en_zzero",
settingType.BOOLEAN,
false,
true,
"Allows the P key to reset zoom. Doesn't work with set zoom levels (requires refresh)",
validator
);
const zoom_levels = new Numlist2(
"Zoom levels",
"zoom_levels",
"Zoom levels",
{
default_values: [0.5, 1, 2, 3, 6, 12],
step: 0.1,
custom_validator: validator
}
);
this.unl_zoom = new SettingGroup({
speed: new Setting(
"Zoom speed",
"unl_zoom_speed",
settingType.NUMBER,
false,
2,
"The zoom magnitude (as the multiplier to the zoom level every time zoom is used)",
validator
),
pan_mode_sel
)
const canvas_div = document.getElementById("canvasDiv")
canvas_div.style.backgroundColor = colour_setting?.value ?? "#252525"
canvas_div.appendChild(container)
}
function rescale(){
log_info()
const scale = zoom_levels[zoom_level]
const x = zoom_panning[0] * (pixelSize * scale)
const y = zoom_panning[1] * (pixelSize * scale)
gameCanvas.style.transform = `translate(${x}px, ${y}px) translateX(-50%) scale(${scale})`
}
function log_info(){
// Values are negated to make them more intuitive
const x_pan = (-zoom_panning[0]).toString().padEnd(4)
const y_pan = (-zoom_panning[1]).toString().padEnd(4)
if (zoom_data_div === null){ return; }
zoom_data_div.innerText = ""
zoom_data_div.innerText += `Scale: ${zoom_levels[zoom_level]}x\n`
zoom_data_div.innerText += `Pan : ${x_pan}, ${y_pan}`
}
function patch_keybinds(){
// Be more granular at higher zoom levels
const speed_a = () => zoom_level > 3 ? 5 : 10
const speed_b = () => zoom_level > 3 ? 10 : 20
keybinds["9"] = () => handle_zoom("in")
keybinds["0"] = () => handle_zoom("out")
keybinds["w"] = () => handle_pan("up", speed_a())
keybinds["a"] = () => handle_pan("left", speed_a())
keybinds["s"] = () => handle_pan("down", speed_a())
keybinds["d"] = () => handle_pan("right", speed_a())
keybinds["W"] = () => handle_pan("up", speed_b())
keybinds["A"] = () => handle_pan("left", speed_b())
keybinds["S"] = () => handle_pan("down", speed_b())
keybinds["D"] = () => handle_pan("right", speed_b())
}
function patch_ui(){
add_css()
add_zoom_floaters()
zoom_data_div = document.createElement("div")
zoom_data_div.id = "zm_data_div"
document.getElementById("logDiv").prepend(zoom_data_div)
const controls_table = document.getElementById("controlsTable").lastElementChild
controls_table.insertAdjacentHTML("beforeBegin",`
<tr>
<td>Zoom in/out</td>
<td>
<kbd>9</kbd>/
<kbd>0</kbd>
</td>
</tr>
<tr>
<td>Pan</td>
<td>
<kbd>W</kbd>
<kbd>A</kbd>
<kbd>S</kbd>
<kbd>D</kbd>
</td>
</tr>
<tr>
<td>Pan (fast)</td>
<td>
<kbd>Shift</kbd> +
<kbd>W</kbd>
<kbd>A</kbd>
<kbd>S</kbd>
<kbd>D</kbd>
</td>
</tr>
`)
}
// Redefine to give correct numbers when zoomed
window.getMousePos = (canvas, evt) => {
if (evt.touches) {
evt.preventDefault();
evt = evt.touches[0];
isMobile = true;
min: new Setting(
"Zoom limit (min)",
"unl_zlim_min",
settingType.NUMBER,
false,
0.25,
"The lower zoom limit (reducing may lead to rounding error coming back from very low levels)",
validator
),
max: new Setting(
"Zoom limit (max)",
"unl_zlim_max",
settingType.NUMBER,
false,
25,
"The upper zoom limit (reducing may lead to rounding error coming back from very high levels)",
validator
)
});
this.zoom = new MultiSetting(
"Zoom mode",
"zoom_mode",
{},
zoom_levels,
this.unl_zoom
);
settings_tab.registerSettings(
void 0,
this.canvas_bkg
);
settings_tab.registerSettings(
"Controls",
this.use_ijkl,
this.show_floater,
this.pan_zeroing_en,
this.zoom_zeroing_en
);
settings_tab.registerSettings(
"Zoom",
this.zoom
);
settings_tab.registerSettings(
"Panning",
this.cpan_speed,
this.fpan_speed,
this.upan_speed
);
settingsManager.registerTab(settings_tab);
}
const rect = canvas.getBoundingClientRect();
};
let x = (evt.clientX - rect.left) / zoom_levels[zoom_level];
let y = (evt.clientY - rect.top) / zoom_levels[zoom_level];
// src/handler.ts
var Handler = class {
settings;
patcher;
zoom_panning = [0, 0];
zoom_level;
constructor(settings, patcher) {
this.settings = settings;
this.patcher = patcher;
this.zoom_level = 1;
this.patch_keybinds();
this.patch_floater();
window.getMousePos = (canvas2, evt) => {
if (evt.touches) {
evt.preventDefault();
evt = evt.touches[0];
isMobile = true;
}
const rect = canvas2.getBoundingClientRect();
const clx = evt.clientX;
const cly = evt.clientY;
let x = (clx - rect.left) / this.scale();
let y = (cly - rect.top) / this.scale();
x = Math.floor(x / canvas2.clientWidth * (width + 1));
y = Math.floor(y / canvas2.clientHeight * (height + 1));
return { x, y };
};
runAfterReset(() => {
this.zoom_level = 1;
this.zoom_panning = [0, 0];
this.update();
});
}
handle_zoom(direction) {
if (this.settings.zoom.value == 0) {
switch (direction) {
case "in":
if (!(this.zoom_level + 1 in this.settings.zoom.settings[0].value)) {
break;
}
this.zoom_level += 1;
break;
case "out":
if (!(this.zoom_level - 1 in this.settings.zoom.settings[0].value)) {
break;
}
this.zoom_level -= 1;
break;
}
} else {
const settings = this.settings.zoom.settings[1].settings;
const speed = settings.speed.value;
const min = settings.min.value;
const max = settings.max.value;
switch (direction) {
case "in":
if (this.zoom_level * speed > max) break;
this.zoom_level *= speed;
break;
case "out":
if (this.zoom_level / speed < min) break;
this.zoom_level /= speed;
break;
}
this.zoom_level = Number(this.zoom_level.toPrecision(3));
}
this.update();
}
handle_pan(direction, speed) {
switch (direction) {
case "right":
this.zoom_panning[0] -= speed;
break;
case "left":
this.zoom_panning[0] += speed;
break;
case "up":
this.zoom_panning[1] += speed;
break;
case "down":
this.zoom_panning[1] -= speed;
break;
}
this.update();
}
scale() {
return this.settings.zoom.value == 0 ? this.settings.zoom.settings[0].value[this.zoom_level] : this.zoom_level;
}
update() {
this.log_info();
const x = this.zoom_panning[0] * (pixelSize * this.scale());
const y = this.zoom_panning[1] * (pixelSize * this.scale());
canvas.style.transform = `translate(${x}px, ${y}px) translateX(-50%) scale(${this.scale()})`;
}
log_info() {
const x_pan = (-this.zoom_panning[0]).toString().padEnd(4);
const y_pan = (-this.zoom_panning[1]).toString().padEnd(4);
this.patcher.zoom_data_div.innerText = "";
this.patcher.zoom_data_div.innerText += `Scale: ${this.scale()}x
`;
this.patcher.zoom_data_div.innerText += `Pan : ${x_pan}, ${y_pan}`;
}
kbd_speed_noshift(ev) {
return ev.altKey ? this.settings.upan_speed.value : this.settings.cpan_speed.value;
}
patch_keybinds() {
const pan_keys = this.settings.use_ijkl.value ? ["i", "j", "k", "l"] : ["w", "a", "s", "d"];
const pan_keys_upper = this.settings.use_ijkl.value ? ["I", "J", "K", "L"] : ["W", "A", "S", "D"];
keybinds["9"] = () => this.handle_zoom("in");
keybinds["0"] = () => this.handle_zoom("out");
keybinds[pan_keys[0]] = (ev) => this.handle_pan("up", this.kbd_speed_noshift(ev));
keybinds[pan_keys[1]] = (ev) => this.handle_pan("left", this.kbd_speed_noshift(ev));
keybinds[pan_keys[2]] = (ev) => this.handle_pan("down", this.kbd_speed_noshift(ev));
keybinds[pan_keys[3]] = (ev) => this.handle_pan("right", this.kbd_speed_noshift(ev));
keybinds[pan_keys_upper[0]] = () => this.handle_pan("up", this.settings.fpan_speed.value);
keybinds[pan_keys_upper[1]] = () => this.handle_pan("left", this.settings.fpan_speed.value);
keybinds[pan_keys_upper[2]] = () => this.handle_pan("down", this.settings.fpan_speed.value);
keybinds[pan_keys_upper[3]] = () => this.handle_pan("right", this.settings.fpan_speed.value);
if (this.settings.pan_zeroing_en.value) {
keybinds["q"] = () => {
this.zoom_panning = [0, 0];
this.update();
};
}
if (this.settings.zoom_zeroing_en.value) {
keybinds["p"] = () => {
if (this.settings.zoom.value == 1) this.zoom_level = 1;
this.update();
};
}
}
floater_speed() {
switch (this.patcher.panmode_sel.innerText) {
case "C":
return this.settings.cpan_speed.value;
case "F":
return this.settings.fpan_speed.value;
case "U":
return this.settings.upan_speed.value;
default:
return 0;
}
}
patch_floater() {
function patch(id, fn) {
document.getElementById(id).onclick = fn;
}
patch("zm_floater_zi", () => this.handle_zoom("in"));
patch("zm_floater_zo", () => this.handle_zoom("out"));
patch("zm_floater_u", () => this.handle_pan("up", this.floater_speed()));
patch("zm_floater_d", () => this.handle_pan("down", this.floater_speed()));
patch("zm_floater_l", () => this.handle_pan("left", this.floater_speed()));
patch("zm_floater_r", () => this.handle_pan("right", this.floater_speed()));
}
};
x = Math.floor((x / canvas.clientWidth) * (width+1));
y = Math.floor((y / canvas.clientHeight) * (height+1));
// assets/numlist.css
var numlist_default = "#settingsMenu .zm_nml_btn_container button { font-size: 2em; padding: 0px; margin: 0px;}\r\n#settingsMenu .zm_nml_icontainer { align-self: center }\r\n#settingsMenu .zm_nml_setting { display: grid; grid-template-columns: 7em 1fr;}\r\n\r\n#settingsMenu .zm_nml_setting span {\r\n input { width: 2em; margin-right: 4px; margin-bottom: 4px;}\r\n \r\n input:focus {\r\n outline: none;\r\n box-shadow: none;\r\n border-color: white;\r\n }\r\n}";
return {x:x, y:y};
// assets/main.css
var main_default = '#zm_data_div { margin-bottom: 10px }\r\n#canvasDiv { overflow: hidden; background-color: var(--opac-85) }\r\n\r\n@media(pointer=coarse){\r\n #zm_floater_container#zm_floater_container { \r\n width: 40%;\r\n height: auto;\r\n }\r\n #zm_floater_container:has(#zm_collapse[data-collapsed="true"]){\r\n width: calc(40% / 3);\r\n }\r\n}\r\n\r\n@media(pointer:coarse) and (orientation:landscape){\r\n #zm_floater_container#zm_floater_container {\r\n width: auto;\r\n top: 5px;\r\n }\r\n #zm_floater_container:has(#zm_collapse[data-collapsed="true"]){\r\n width: calc(40% / 3);\r\n }\r\n}\r\n\r\n#colorSelector { z-index: 1; right: 5px }\r\n#zm_floater_container {\r\n position: absolute;\r\n display: grid;\r\n\r\n right: 5px;\r\n bottom: 5px;\r\n height: 100px;\r\n aspect-ratio: 1;\r\n\r\n max-width: 200px;\r\n max-height: 200px;\r\n\r\n border: 2px solid white;\r\n background-color: black;\r\n font-size: 120%;\r\n\r\n button { text-align: center; border: 0px solid white }\r\n\r\n button:where([data-pos="tl"]) { border-width: 0px 2px 2px 0px };\r\n button:where([data-pos="tr"]) { border-width: 2px 2px 0px 0px };\r\n button:where([data-pos="bl"]) { border-width: 0px 0px 2px 2px };\r\n button:where([data-pos="br"]) { border-width: 2px 0px 0px 2px };\r\n}\r\n#zm_floater_container:has(#zm_collapse[data-collapsed="true"]) {\r\n height: 50px;\r\n \r\n button:not(#zm_collapse) { display: none; }\r\n}\r\n#canvasDiv:has(#colorSelector[style *= "block"]) #zm_floater_container {\r\n bottom: 50px;\r\n}\r\n\r\n.zm_corner { border: 2px solid white; }\r\n\r\n#zm_collapse {\r\n grid-row: 3;\r\n grid-column: 3;\r\n}\r\n#zm_collapse[data-collapsed="true"] {\r\n grid-row: 1;\r\n grid-column: 1;\r\n border-width: 0px;\r\n}';
// assets/multisetting.css
var multisetting_default = '.zm_ms_row {\r\n display: grid;\r\n grid-template-columns: 2.2em 1fr; \r\n}\r\n\r\n.zm_ms_row[data-current="false"] {\r\n .zm_ms_selbtn { color: transparent }\r\n}\r\n\r\n.zm_ms_selbtn.zm_ms_selbtn:not(#_) {\r\n height: 100%;\r\n width: calc(100% - 10px);\r\n\r\n margin-right: 2px;\r\n padding: 0px;\r\n\r\n border: 2px solid var(--theme);\r\n font-size: 1.5em;\r\n}';
// assets/ctrl_info.html
var ctrl_info_default = "<tr>\r\n <td>Zoom in/out</td>\r\n <td>\r\n <kbd>9</kbd>/\r\n <kbd>0</kbd>\r\n </td>\r\n</tr>\r\n<tr>\r\n <td>Pan</td>\r\n <td>\r\n <kbd>W</kbd>\r\n <kbd>A</kbd>\r\n <kbd>S</kbd>\r\n <kbd>D</kbd>\r\n </td>\r\n</tr>\r\n<tr>\r\n <td>Pan (fast)</td>\r\n <td>\r\n <kbd>Shift</kbd> + \r\n <kbd>W</kbd>\r\n <kbd>A</kbd>\r\n <kbd>S</kbd>\r\n <kbd>D</kbd>\r\n </td>\r\n</tr>";
// assets/floater.html
var floater_default = '<div id="zm_floater_container">\r\n <button id="zm_floater_u" style="grid-area: 1 / 2;">&uarr;</button>\r\n <button id="zm_floater_d" style="grid-area: 3 / 2;">&darr;</button>\r\n <button id="zm_floater_l" style="grid-area: 2 / 1;">&larr;</button>\r\n <button id="zm_floater_r" style="grid-area: 2 / 3;">&rarr;</button>\r\n \r\n <button id="zm_floater_zi" data-pos="tl" style="grid-area: 1 / 1;">+</button>\r\n <button id="zm_floater_zo" data-pos="bl" style="grid-area: 1 / 3;">-</button>\r\n\r\n <button id="zm_collapse" data-pos="br">#</button>\r\n <button id="zm_panmode_sel" data-pos="tr" style="grid-area: 3 / 1;">C</button>\r\n</div>';
// assets/nlist_spinner.png
var nlist_spinner_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAYCAYAAADH2bwQAAAAcklEQVQokcWSXQrAIAyDv8oOoPe/49wJzB7coIg/jA2WPhQ1TdOiATsThNmjJ8QV4XjdokIkRHqiEAF2NAgoSw8GlCuD3K3zYEzgFdSQBbA15LaYQN1i9lU+3y16CgDqjSl/MKBoMIk5DyNk46sf9SfhBITwI86iGhy9AAAAAElFTkSuQmCC";
// assets/spinner.css.ts
var CSS = `
#betterSettings\\/div\\/zoom\\.js input::-webkit-inner-spin-button,
#betterSettings\\/div\\/zoom\\.js input::-webkit-outer-spin-button {
-webkit-appearance: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 0.75em;
background: #000 url(${nlist_spinner_default}) no-repeat center center;
background-size: 100%;
border-left: 2px solid var(--theme);
image-rendering: pixelated;
opacity: 0.8;
}
#betterSettings\\/div\\/zoom\\.js input::-webkit-inner-spin-button:hover,
#betterSettings\\/div\\/zoom\\.js input::-webkit-outer-spin-button:active {
border-left: 2px solid white;
opacity: 1;
}
`;
var spinner_css_default = CSS;
runAfterReset(() => {
window.zoom_level = 1
rescale()
})
// src/patcher.ts
var Patcher = class {
zoom_data_div;
floater_div;
canvas_div;
settings;
panmode_sel;
constructor(settings) {
this.settings = settings;
const style_div = document.createElement("style");
style_div.innerHTML = main_default;
document.head.appendChild(style_div);
dependOn("betterSettings.js", () => {
const style_div2 = document.createElement("style");
style_div2.innerHTML = numlist_default + multisetting_default + spinner_css_default;
document.head.appendChild(style_div2);
});
this.canvas_div = document.getElementById("canvasDiv");
this.canvas_div.insertAdjacentHTML("beforeend", floater_default);
this.floater_div = document.getElementById("zm_floater_container");
this.panmode_sel = document.getElementById("zm_panmode_sel");
this.panmode_sel.onclick = () => {
switch (this.panmode_sel.innerText) {
case "C":
this.panmode_sel.innerText = "F";
break;
case "F":
this.panmode_sel.innerText = "U";
break;
case "U":
this.panmode_sel.innerText = "C";
break;
}
};
const collapse_btn = document.getElementById("zm_collapse");
collapse_btn.onclick = () => {
collapse_btn.dataset.collapsed = collapse_btn.dataset.collapsed == "true" ? "false" : "true";
};
this.zoom_data_div = document.createElement("div");
this.zoom_data_div.id = "zm_data_div";
document.getElementById("logDiv")?.prepend(this.zoom_data_div);
document.getElementById("controlsTable")?.lastElementChild?.insertAdjacentHTML("beforebegin", ctrl_info_default);
this.update_from_settings();
runAfterLoad(() => {
const cb = this.update_from_settings.bind(this);
for (const elem of document.querySelectorAll("#betterSettings\\/div\\/zoom\\.js span.setting-span input")) {
elem.addEventListener(elem.classList.contains("toggleInput") ? "click" : "change", cb);
}
});
}
update_from_settings() {
this.floater_div.style.display = this.settings.show_floater.value ? "grid" : "none";
this.canvas_div.style.backgroundColor = this.settings.canvas_bkg.value ?? "#252525";
}
};
runAfterLoad(() => {
patch_keybinds()
patch_ui()
})
// src/main.ts
dependOn("betterSettings.js", () => {
const on_change = { cb: () => {
} };
const settings_manager = new CustomSettingsManager(on_change);
runAfterLoad(() => {
const patcher = new Patcher(settings_manager);
const handler = new Handler(settings_manager, patcher);
});
}, true);
})();

322
mods/zoom_legacy.js Normal file
View File

@ -0,0 +1,322 @@
const zoom_levels = [
0.5,
1,
2,
3,
6,
12
]
window.zoom_data_div = null
window.zoom_level = 1
window.zoom_panning = [0,0]
let colour_setting;
dependOn("betterSettings.js", () => {
const settings_tab = new SettingsTab("zoom.js");
colour_setting = new Setting(
"Canvas background",
"canvas_bkg",
settingType.COLOR,
false,
defaultValue="#252525"
);
settings_tab.registerSettings(undefined, colour_setting)
settingsManager.registerTab(settings_tab)
})
function handle_zoom(direction){
switch (direction){
case "in":
if (!(zoom_level+1 in zoom_levels)) { break; }
window.zoom_level += 1
break;
case "out":
if (!(zoom_level-1 in zoom_levels)) { break; }
window.zoom_level -= 1
break;
}
rescale()
}
function handle_pan(direction, speed){
switch (direction){
case "right":
zoom_panning[0] -= speed
break;
case "left":
zoom_panning[0] += speed
break;
case "up":
zoom_panning[1] += speed
break;
case "down":
zoom_panning[1] -= speed
break;
}
rescale()
}
function gen_button(row, col, html, click, nopos, id){
const elem = document.createElement("button")
if (!nopos){
elem.style.gridColumn = row
elem.style.gridRow = col
}
if (id) { elem.id = id }
// Table for the data-pos to assign (row major). If null, don't add.
const data_pos_map = [
["tl", null, "tr"],
[null, null, null],
["bl", null, "br"]
]
elem.innerHTML = html
elem.onclick = click
if (data_pos_map[row-1][col-1] !== null) {
elem.dataset.pos = data_pos_map[row-1][col-1]
}
return elem
}
function add_css(){
const CSS = `
#zm_data_div { margin-bottom: 10px }
#canvasDiv { overflow: hidden; background-color: var(--opac-85) }
@media(pointer=coarse){
#zm_floater_container#zm_floater_container {
width: 40%;
height: auto;
}
#zm_floater_container:has(#zm_collapse[data-collapsed="true"]){
width: calc(40% / 3);
}
}
@media(pointer:coarse) and (orientation:landscape){
#zm_floater_container#zm_floater_container {
width: auto;
top: 5px;
}
#zm_floater_container:has(#zm_collapse[data-collapsed="true"]){
width: calc(40% / 3);
}
}
#colorSelector { z-index: 1; right: 5px }
#zm_floater_container {
position: absolute;
display: grid;
right: 5px;
bottom: 5px;
height: 100px;
aspect-ratio: 1;
max-width: 200px;
max-height: 200px;
border: 2px solid white;
background-color: black;
font-size: 120%;
button { text-align: center; border: 0px solid white }
button:where([data-pos="tl"]) { border-width: 0px 2px 2px 0px };
button:where([data-pos="tr"]) { border-width: 2px 2px 0px 0px };
button:where([data-pos="bl"]) { border-width: 0px 0px 2px 2px };
button:where([data-pos="br"]) { border-width: 2px 0px 0px 2px };
}
#zm_floater_container:has(#zm_collapse[data-collapsed="true"]) {
height: 50px;
button:not(#zm_collapse) {
display: none;
}
}
#canvasDiv:has(#colorSelector[style *= "block"]) #zm_floater_container {
bottom: 50px;
}
.zm_corner { border: 2px solid white; }
#zm_collapse {
grid-row: 3;
grid-column: 3;
}
#zm_collapse[data-collapsed="true"] {
grid-row: 1;
grid-column: 1;
border-width: 0px;
}
`
const style_div = document.createElement("style")
style_div.innerHTML = CSS
document.head.appendChild(style_div)
}
function add_zoom_floaters(){
const container = document.createElement("div")
container.id = "zm_floater_container"
// Pan mode selector (C: Coarse F: Fine)
const pan_mode_sel = gen_button(
1,3, "C",
(evt) => {
evt.target.dataset.mode = evt.target.dataset.mode == "F" ? "C" : "F"
evt.target.innerText = evt.target.dataset.mode
},
false,
"zm_panmode_sel"
)
const speed = () =>
(window.zoom_level > 3 ? 5 : 10) * // More granular at higher zoom levels
(pan_mode_sel.dataset.mode == "F" ? 0.25 : 1) // Increase granularity in fine mode
container.append(
// Direction buttons
gen_button(2,1, "&uarr;", () => handle_pan("up" ,speed())),
gen_button(1,2, "&larr;", () => handle_pan("left" ,speed())),
gen_button(3,2, "&rarr;", () => handle_pan("right" ,speed())),
gen_button(2,3, "&darr;", () => handle_pan("down" ,speed())),
// Zoom buttons
gen_button(1,1, "+", () => handle_zoom("in")),
gen_button(3,1, "-", () => handle_zoom("out")),
// Collapse button
gen_button(
3,3, "#",
(evt) => {
evt.target.dataset.collapsed = evt.target.dataset.collapsed == "true"
? "false"
: "true"
},
true,
"zm_collapse"
),
pan_mode_sel
)
const canvas_div = document.getElementById("canvasDiv")
canvas_div.style.backgroundColor = colour_setting?.value ?? "#252525"
canvas_div.appendChild(container)
}
function rescale(){
log_info()
const scale = zoom_levels[zoom_level]
const x = zoom_panning[0] * (pixelSize * scale)
const y = zoom_panning[1] * (pixelSize * scale)
gameCanvas.style.transform = `translate(${x}px, ${y}px) translateX(-50%) scale(${scale})`
}
function log_info(){
// Values are negated to make them more intuitive
const x_pan = (-zoom_panning[0]).toString().padEnd(4)
const y_pan = (-zoom_panning[1]).toString().padEnd(4)
if (zoom_data_div === null){ return; }
zoom_data_div.innerText = ""
zoom_data_div.innerText += `Scale: ${zoom_levels[zoom_level]}x\n`
zoom_data_div.innerText += `Pan : ${x_pan}, ${y_pan}`
}
function patch_keybinds(){
// Be more granular at higher zoom levels
const speed_a = () => zoom_level > 3 ? 5 : 10
const speed_b = () => zoom_level > 3 ? 10 : 20
keybinds["9"] = () => handle_zoom("in")
keybinds["0"] = () => handle_zoom("out")
keybinds["w"] = () => handle_pan("up", speed_a())
keybinds["a"] = () => handle_pan("left", speed_a())
keybinds["s"] = () => handle_pan("down", speed_a())
keybinds["d"] = () => handle_pan("right", speed_a())
keybinds["W"] = () => handle_pan("up", speed_b())
keybinds["A"] = () => handle_pan("left", speed_b())
keybinds["S"] = () => handle_pan("down", speed_b())
keybinds["D"] = () => handle_pan("right", speed_b())
}
function patch_ui(){
add_css()
add_zoom_floaters()
zoom_data_div = document.createElement("div")
zoom_data_div.id = "zm_data_div"
document.getElementById("logDiv").prepend(zoom_data_div)
const controls_table = document.getElementById("controlsTable").lastElementChild
controls_table.insertAdjacentHTML("beforeBegin",`
<tr>
<td>Zoom in/out</td>
<td>
<kbd>9</kbd>/
<kbd>0</kbd>
</td>
</tr>
<tr>
<td>Pan</td>
<td>
<kbd>W</kbd>
<kbd>A</kbd>
<kbd>S</kbd>
<kbd>D</kbd>
</td>
</tr>
<tr>
<td>Pan (fast)</td>
<td>
<kbd>Shift</kbd> +
<kbd>W</kbd>
<kbd>A</kbd>
<kbd>S</kbd>
<kbd>D</kbd>
</td>
</tr>
`)
}
// Redefine to give correct numbers when zoomed
window.getMousePos = (canvas, evt) => {
if (evt.touches) {
evt.preventDefault();
evt = evt.touches[0];
isMobile = true;
}
const rect = canvas.getBoundingClientRect();
let x = (evt.clientX - rect.left) / zoom_levels[zoom_level];
let y = (evt.clientY - rect.top) / zoom_levels[zoom_level];
x = Math.floor((x / canvas.clientWidth) * (width+1));
y = Math.floor((y / canvas.clientHeight) * (height+1));
return {x:x, y:y};
}
runAfterReset(() => {
window.zoom_level = 1
rescale()
})
runAfterLoad(() => {
patch_keybinds()
patch_ui()
})

233
weaponsRewrite.js Normal file
View File

@ -0,0 +1,233 @@
dependOn("betterSettings.js", () => {
const tabweapons = new SettingsTab("weapons.js");
enablestartupprompt = new Setting("Startup prompt", "startup_prompt", settingType.BOOLEAN, false, defaultValue=true, "The prompt requesting you to add velocity.js, (unavailable for steam edition)");
tabweapons.registerSetting(enablestartupprompt);
settingsManager.registerTab(tabweapons);
runAfterLoad(async () => {
window.setTimeout(async () => {
if (!enabledMods.includes("mods/velocity.js") && standaloneType !== "steam" && enablestartupprompt.value === true){
_jaydalert("velocity.js is recommended for weapons.js to function in its intended way.");
}
},)
})
},true)
async function _weaponsjsprompt(message, defaultValue = "") {
return new Promise(resolve => {
promptInput(message, (result) => {
resolve(result);
}, "weapons.js is asking you...", defaultValue);
})
}
async function _jaydalert(message) {
promptText(message, undefined, "Jayd:");
}
async function _weaponsjsdir(message) {
promptDir(message, undefined, "weapons.js is asking you...");
}
elements.tsar_bomba = {
color: "#969696",
tick: (pixel) => {
tryMove(pixel, pixel.x, pixel.y+1)
for (var y = 1; y < 4; y++) {
if (!isEmpty(pixel.x, pixel.y + y, false)) {
explodeAt(pixel.x,pixel.y,150,"plasma")
}
}
},
category: "weapons.js",
state: "solid",
density: 1300,
excludeRandom: true,
cooldown: defaultCooldown
},
elements.missile_left = {
color: "#313131",
category: "weapons.js",
state: "solid",
behavior: [
"EX:20>missile_shrapnel|XX|XX|XX|XX|XX|CR:smoke"
],
ignore: "missile_left",
tick: function(pixel) {
var circlec = circleCoords(pixel.x, pixel.y, 3)
for (var i = 0; i < circlec.length; i++){
var coord = circlec[i]
var x = coord.x
var y = coord.y
if (!(isEmpty(x, y, true) || (x == pixel.x && y == pixel.y) || elements[pixelMap[x][y].element].state == "gas" || pixelMap[x][y].element == "missile_left")){
explodeAt(pixel.x,pixel.y,20,"missile_shrapnel")
}
}
for (var i=0; i<3; i++) {
tryMove(pixel, pixel.x-1, pixel.y)
}
},
density: 1300,
excludeRandom: true,
cooldown: defaultCooldown
},
elements.missile_right = {
color: "#313131",
category: "weapons.js",
state: "solid",
behavior: [
"CR:smoke|XX|XX|XX|XX|XX|EX:20>missile_shrapnel"
],
ignore: "missile_right",
tick: function(pixel) {
var circlec = circleCoords(pixel.x, pixel.y, 3)
for (var i = 0; i < circlec.length; i++){
var coord = circlec[i]
var x = coord.x
var y = coord.y
if (!(isEmpty(x, y, true) || (x == pixel.x && y == pixel.y) || elements[pixelMap[x][y].element].state == "gas")){
explodeAt(pixel.x,pixel.y,20,"missile_shrapnel")
}
}
for (var i=0; i<3; i++) {
tryMove(pixel, pixel.x+1, pixel.y)
}
},
density: 1300,
excludeRandom: true,
cooldown: defaultCooldown
}
var target = [,];
var tgt = "head";
elements.tracking_missile = {
color: "#323232",
category: "weapons.js",
behavior: [
"XX","XX","CR:smoke"
],
onSelect: async () => {
var answer1 = await _weaponsjsprompt("Please input the target.",(tgt||undefined));
if (!answer1) {return}
tgt = answer1;
},
tick: (pixel) => {
var circlec = circleCoords(pixel.x, pixel.y, 3)
for (var i = 0; i < circlec.length; i++){
var coord = circlec[i]
var xe = coord.x
var ye = coord.y
if (!(isEmpty(xe, ye, true) || (xe == pixel.x && ye == pixel.y) || elements[pixelMap[xe][ye].element].state == "gas" || pixelMap[xe][ye].element == "tracking_missile")){
explodeAt(pixel.x,pixel.y,20,"missile_shrapnel")
}
}
for (var x = 1; x < width; x++) {
for (var y = 1; y < height; y++) {
if (!isEmpty(x,y)) {
if (pixelMap[x][y].element===tgt) {
target = [pixelMap[x][y].x, pixelMap[x][y].y];
}
}
}
}
if (pixel.x != target[0] || pixel.y != target[1]) {
let {x, y} = pixel;
const empty = checkForEmptyPixels(x, y);
const [tX, tY] = target;
let bestVal = Math.sqrt(Math.pow(tX - x, 2) + Math.pow(tY - y, 2));
let best = null;
for (const pixelPair of empty) {
const [x_, y_] = [x + pixelPair[0], y + pixelPair[1]];
const c = Math.sqrt(Math.pow(tX - x_, 2) + Math.pow(tY - y_, 2));
if (c < bestVal) {
bestVal = c;
best = pixelPair;
}
}
if (best) {
tryMove(pixel, x + best[0]*2, y + best[1]*2, undefined, true);
}
}
}
},
elements.missile_shrapnel = {
color: "#979ea3",
behavior: [
"XX|XX|XX",
"XX|EX:5 %20|XX",
"M2%20|M1%20|M2%20",
],
burn: 90,
burnTime: 100,
density: 2000,
conduct: 1,
state: "solid",
category: "weapons.js"
},
elements.cluster_nuke = {
color: "#323232",
category: "weapons.js",
behavior: behaviors.POWDER,
maxSize: 1,
cooldown: defaultCooldown,
tick: (pixel) => {
for (var y = 1; y < 25; y++) {
if (!isEmpty(pixel.x, pixel.y + y, false)) {
explodeAt(pixel.x,pixel.y,25,["dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","dirty_bomb","nuke",])
}
}
}
}
// let ammo1 = 1;
// let rdir = 1;
// let ammoLoaded = "";
// elements.railgun = {
// category: "weapons.js",
// behavior: behaviors.WALL,
// onSelect: async (pixel) => {
// var answer1 = await _weaponsjsprompt("Please input the ammo type. \n \n <1 for Armor-Piercing ammo> \n <2 for High-Explosive ammo.>",(ammo1||undefined));
// if (!answer1) {return}
// ammo1 = answer1;
// var answer2 = await _weaponsjsdir("Please input the direction.",(rdir||undefined));
// if (!answer2) {
// console.log(answer2)
// return}
// rdir = answer2;
// },
// tick: async (pixel) => {
// ammoLoaded = "armor_piercing_shell";
// if(ammo1 === 1){
// ammoLoaded = "armor_piercing_shell"
// }
// else if (ammo1 === 2){
// ammoLoaded = "high_explosive_shell"
// }
// if (pixel.charge){
// if(rdir === 1){
// createPixel(ammoLoaded, pixel.x, pixel.y-1);
// }
// if (rdir === 2){
// createPixel(ammoLoaded, pixel.x, pixel.y+1);
// }
// if (rdir === 3){
// createPixel(ammoLoaded, pixel.x-1, pixel.y);
// }
// if (rdir === 4){
// createPixel(ammoLoaded, pixel.x+1, pixel.y);
// }
// }
// doDefaults(pixel);
// },
// color: "#c9c9c9",
// conduct: 1,
// hardness: 8,
// },
// elements.armor_piercing_shell = {
// category: "ammunition",
// color: "#ffc954",
// hardness: 0.9,
// }
// elements.high_explosive_shell = {
// category: "ammunition",
// color: "#ffc954",
// hardness: 0.6,
// }