This commit is contained in:
slweeb 2023-12-28 19:03:32 -05:00
commit 5c5d3a1752
9 changed files with 394 additions and 9 deletions

View File

@ -8,11 +8,35 @@ message: >-
metadata from this file.
type: software
authors:
- given-names: R74n
email: contact@r74n.com
affiliation: R74n
- name: R74n
email: contact@R74n.com
date-start: '2017-05-02'
website: 'https://r74n.com/'
identifiers:
- type: doi
value: 10.17605/OSF.IO/H7TDY
- type: swh
value: 'swh:1:rev:5a5813a8f4f418540f1bdb765d293735541bf7fd'
- type: url
value: 'https://sandboxels.r74n.com/'
- type: doi
value: 10.5281/zenodo.10044909
- type: other
value: /g/11spmybz10
description: KGMID
- type: url
value: 'https://purl.org/r74n/sandboxels'
description: PURL
- type: url
value: 'https://w3id.org/r74n/sandboxels'
description: W3ID
repository-code: 'https://github.com/R74nCom/sandboxels'
url: 'https://sandboxels.r74n.com'
abstract: >-
Sandboxels is a free falling-sand simulator that can be
played in your browser. It features heat simulation,
electricity, density, chemical reactions, cooking, and
fire spread.
keywords:
- R74n
- Sandboxels

View File

@ -115,13 +115,13 @@
<!----><tr><td class="modCat" colspan="3">Tools & Settings</td></tr><!---->
<tr><td>adjustablepixelsize.js</td><td>Allows you to set the pixelSize with a URL parameter</td><td>Alice</td></tr>
<tr><td>betaworldgen.js</td><td>adds a more advanced world generation to the game</td><td>Alex</td></tr>
<tr><td>betterModManager.js</td><td>Improvements to the Mod Manager</td><td>ggod</td></tr>
<tr><td>betterSettings.js</td><td>Adds additional settings and functionality</td><td>ggod</td></tr>
<tr><td>betterStats.js</td><td>Separate “real” and “set” TPS, meaning you can see what the TPS actually is, instead of only seeing what its set to</td><td>mollthecoder</td></tr>
<tr><td>change.js</td><td>Adds a tool that only replaces existing pixels</td><td>Alice</td></tr>
<tr><td>color_tools.js</td><td>Adds tools that manipulate colors</td><td>Alice</td></tr>
<tr><td>controllable_pixel_test.js</td><td>Adds a pixel that can be controlled with the keyboard keys. <a href="https://github.com/R74nCom/sandboxels/commit/58dfa9477f2ed7ec9c44b00a35162e7c63bc129c">Read the commit description for more info.</a> [PC ONLY]</td><td>Alice</td></tr>
<tr><td>customexplosion.js</td><td>Added a custom explosion element and interface for it. check out its <a href="https://sandboxels-mods.the-enchanteden.repl.co/Mods/customexplosion.js">source code</a> for how modders can use it.</td><td>Alex</td></tr>
<tr><td>cpt_alt.js</td><td>Adds a more destructive variant of the controllable pixel</td><td>Alice</td></tr>
<tr><td>debugRework.js</td><td>Revamps the Debug tool</td><td>Fioushemastor</td></tr>
<tr><td>delete_all_of_element.js</td><td>Adds a tool that deletes every pixel of the element(s) the user clicks on</td><td>Alice</td></tr>
@ -261,6 +261,7 @@
<tr><td>changeTempReactionParameter.js</td><td>Adds the changeTemp property to modded reactions</td><td>Alice</td></tr>
<tr><td>code_library.js</td><td>Adds functions and variables common to some other mods</td><td>Alice</td></tr>
<tr><td>CrashTestDummy.js</td><td>Originally a test to see if certain code broke the game, but now just adds a tool that turns things into sand</td><td>StellarX20</td></tr>
<tr><td>customexplosion.js</td><td>Added a custom explosion element and interface for it. check out its <a href="https://sandboxels-mods.the-enchanteden.repl.co/Mods/customexplosion.js">source code</a> for how modders can use it.</td><td>Alex</td></tr>
<tr><td>date_test.js</td><td>K-pop idol birthday testing stuff</td><td>Alice</td></tr>
<tr><td>drawPixels_change_test.js</td><td>A test of altering drawPixels(). Gives burning pixels a red overlay similar to the yellow overlay for charged pixels</td><td>Alice</td></tr>
<tr><td>example_mod.js</td><td>An example mod for new modders</td><td><a href="https://R74n.com" class="R74nLink">R74n</a></td></tr>

128
mods/betaworldgen.js Normal file
View File

@ -0,0 +1,128 @@
//This mod was made by Alex the transfem, https://discord.com/users/778753696804765696 on discord and https://www.tiktok.com/@alextheagenenby?_t=8hoCVI3NRhu&_r=1 on tiktok.
function randomAlter(num, list){
let r = Math.floor(Math.random() * list.length);
return (num + list[r]);
}
let avgheight = 0;
let seed = "";
function getSeed(type = "plains", thickness = 15){
seed = "";
console.log(thickness)
if(thickness == 15){
avgheight = Math.floor(Math.random() * (18 - 12 + 1)) + 12;
} else{
avgheight = thickness;
}
console.log(avgheight)
if(type == "plains"){
let location = Math.floor(Math.random(0, pixelMap.length) * 100);
let i = 0;
while (i < pixelMap.length){
if (i !== location){
seed += `${randomAlter(avgheight, [0, 1, 1, 2, 0, 0])}|`;
i += 1;
} else if (i == location){
let height = `${Math.floor(Math.random(40, pixelMap[i].length) * 10)}`;
let prevH = randomAlter(avgheight, [1, 1, 1, 2, 0, 0]);
while (height > prevH){
prevH = randomAlter(prevH, [0, 1, 1, 2, 0, 0, 0, 1]);
seed += `${prevH}|`;
}
i += 1;
}
}
return seed;
}
if(type == "desert"){
let i = 0;
while (i < pixelMap.length){
seed += `${randomAlter(avgheight, [0, 1, 1, 2, 0, 0])}|`;
i += 1;
}
}
return seed;
}
function spawnElements(seed, list, height2 = 1, condition = [1, 1, 0]){
console.log(list);
let width = pixelMap.length - 1;
let element;
let height = pixelMap[1].length - 1;
console.log(seed);
let seedArray = seed.split("|");
console.log(seedArray);
seedArray.splice(seedArray.indexOf(""), 1);
seedArray.splice(pixelMap.length);
console.log(seedArray);
let i = 0;
while (i < seedArray.length - 1){
let ii = 0;
while (ii < seedArray[i]){
if((Math.floor(Math.random() * (condition[0] - condition[1] + 1))) == condition[2]){
if (height2 != 1){
element = list[Math.floor(Math.random() * list.length)];
createPixel(element, (width - 1) - i, (height - (height2 + 1)) - ii);
} else{
element = list[Math.floor(Math.random() * list.length)];
createPixel(element, (width - 1) - i, (height - 1) - ii);
}
}
ii += 1;
}
i += 1;
}
}
function flat(){
let iii = 0;
let flat = "";
while (iii < pixelMap.length){
flat += "1|";
iii += 1;
}
return flat;
}
function processSeed(seed, type = "plains"){
console.log(flat());
let seedsArray = seed.split(":");
console.log(seedsArray);
if(type == "plains"){
spawnElements(seedsArray[0],["rock","rock","rock","rock","rock","rock","metal_scrap","metal_scrap","metal_scrap","gold_coin","uranium","uranium","diamond","rock","iron","iron","iron","aluminum","aluminum","aluminum","aluminum","copper","copper","copper","zinc","zinc","rock","rock","rock","rock","rock","rock","rock","rock","rock","rock","rock","rock","rock","rock","rock"].sort(() => Math.random() - 0.5));
setTimeout(function(){ spawnElements(seedsArray[1], ["dirt"], 24); }, 200);
setTimeout(function(){ spawnElements(flat(),["grass","grass","grass","sapling","flower_seed","grass","grass","pinecone","grass","grass","grass","grass","grass","grass","grass","grass","grass","grass"], 40); }, 300);
} else if(type == "desert"){
spawnElements(seed, ["sand"]);
setTimeout(function(){ spawnElements(flat(), ["cactus"], 40, [6, 0, 3]); }, 100);
}
}
elements.worldGen = {
color: "#FFFFFF",
behavior: elements.erase.behavior,
temp: 2,
category: "tools",
insulate:true,
canPlace: false,
desc: "Generate worlds with random seeds or your own seeds.",
onSelect: function() {
let Seed = prompt("Enter desert or plains random generation! automatically set to plains.");
let regex = /[a-z]/;
if (regex.test(Seed)){
if(Seed.toLowerCase() == "desert"){
processSeed(getSeed("desert", 30), "desert");
}
} else {
if (Seed == ""){
seed = `${getSeed("plains", 20)}:${getSeed("plains", 8)}`
processSeed(seed);
} else{
processSeed(Seed);
}
}
}
}

View File

@ -1,7 +1,15 @@
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//URL
urlParams = new URLSearchParams(window.location.search);
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//Objects
//getKeyByValue code by SO UncleLaz: https://stackoverflow.com/questions/9907419/how-to-get-a-key-in-a-javascript-object-by-its-value
@ -10,6 +18,10 @@
return Object.keys(object).find(key => object[key] === value);
};
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//RNG
//Random integer from 0 to n
@ -77,6 +89,10 @@
return Math.floor(randomFunction() * (max - min + 1)) + min
};
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//Arrays
//Shallow array comparer by SO Tim Down: https://stackoverflow.com/a/10260204
@ -158,6 +174,10 @@
};
};
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//Checks
//Element exists in the elements object
@ -260,6 +280,10 @@
return false;
};
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//Math(s)
//Base n logarithm from https://stackoverflow.com/a/3019290
@ -305,6 +329,10 @@
return (number - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
}
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//Color
function rgbStringToUnvalidatedObject(string) { //turns rgb() to {r,g,b} with no bounds checking
@ -1182,7 +1210,11 @@
//console.log(`Hexed to #${f(0)}${f(8)}${f(4)}`)
return `#${f(0)}${f(8)}${f(4)}`;
};
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//Pixels
function exposedToAir(pixel) {
@ -1540,6 +1572,10 @@
return true;
};
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//World
function breakCircle(x,y,radius,respectHardness=false,changeTemp=false,defaultBreakIntoDust=false) {
@ -1639,6 +1675,10 @@
return true;
};
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//Logic
function xor(c1,c2) {
@ -1651,6 +1691,10 @@
};
};
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//currentPixels operations
function findInCurrentPixels(x,y) {
@ -1710,6 +1754,10 @@
};
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//Sugar functions
function newElement(name="element_name",color="#FF00FF",otherProps={}) {
@ -1722,6 +1770,10 @@
return elements[name];
};
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
//Fixes
//fix -1-caused ghost pixels
@ -1747,4 +1799,16 @@
}
}
}*/
};
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true;
runAfterLoad(function() {
if(!libraryLoaded) {
libraryLoaded = true;
this.libraryLoaded = true;
window.libraryLoaded = true
}
})

View File

@ -1,8 +1,9 @@
const heatfunc = function(pixel){
if (pixel.ogR == null || pixel.ogG == null || pixel.ogB == null){
if (pixel.ogR == null || pixel.ogG == null || pixel.ogB == null || !(pixel.element == pixel.ogElement)){
pixel.ogR = parseInt(pixel.color.slice(4, pixel.color.indexOf(',')), 10)
pixel.ogG = parseInt(pixel.color.slice(pixel.color.indexOf(',') + 1, pixel.color.lastIndexOf(',')), 10)
pixel.ogB = parseInt(pixel.color.slice(pixel.color.lastIndexOf(',') + 1, -1), 10)
pixel.ogElement = pixel.element
}else{
pixel.gethigh = (elements[pixel.element].tempHigh)
pixel.halftemp = ((20+pixel.gethigh)/2)
@ -24,7 +25,7 @@ const heatfunc = function(pixel){
}
};
if (!eLists.metals) { eLists.metals = [] }
eLists.metals = eLists.metals.concat(["iron", "glass", "copper", "gold", "brass","steel","nickel","zinc","silver","aluminum","bronze","metal_scrap","oxidized_copper","tin","lead"])
eLists.metals = eLists.metals.concat(["iron", "glass", "copper", "gold", "brass","steel","nickel","zinc","silver","aluminum","bronze","metal_scrap","oxidized_copper","tin","lead", "rose_gold"])
eLists.metals.forEach(metal => {
const prefunc = elements[metal].tick;
if (!prefunc){

View File

@ -1390,4 +1390,111 @@ elements.blackhole_storage = {
},
movable: false,
conduct: 1,
},
elements.plutonium = {
color: ["#616161", "#4b4949", "#353232", "#211c1c"],
behavior: behaviors.STURDYPOWDER,
category: "powders",
tempHigh: 640,
stateHigh: "molten_plutonium",
state: "solid",
tick: function(pixel){
if (Math.random() < 0.0007) {
changePixel(pixel, "neutron", false);
} else if (Math.random() < 0.0007) {
changePixel(pixel, "uranium", false);
}
},
reactions: {
"neutron": { elem1:"pn_explosion", tempMin:400, chance:0.1 },
"neutron": { temp1: 100, temp2: 100 },
},
density: 19186,
}
elements.molten_plutonium = {
color: ["#6b5133", "#743f26", "#7c2727"],
behavior: behaviors.LIQUID,
category: "states",
state: "liquid",
tempLow: 620,
stateLow: "plutonium",
tick: function(pixel){
if (Math.random() < 0.0007) {
changePixel(pixel, "neutron", false);
} else if (Math.random() < 0.0007) {
changePixel(pixel, "uranium", false);
}
},
reactions: {
"neutron": { elem1:"pn_explosion", tempMin:400, chance:0.1 },
},
density: 16629,
},
elements.neutron.reactions = {
"uranium": { temp2:100 },
"plutonium": { temp2: 100 }
},
elements.pn_explosion = {
color: ["#ffb48f","#ffd991","#ffad91"],
behavior: [
"XX|XX|XX",
"XX|EX:80>plasma,plasma,plasma,plasma,radiation,rad_steam,neutron|XX",
"XX|XX|XX",
],
temp: 100000000,
category: "energy",
state: "gas",
density: 1000,
excludeRandom: true,
hidden: true,
alias: "plutonium nuclear explosion",
noMix: true
},
elements.smasher = {
color: "#606060",
behavior: behaviors.WALL,
category: "machines",
tick: function(pixel){
for (var i = 0; i < squareCoords.length; i++) {
var coord = squareCoords[i];
var x = pixel.x+coord[0];
var y = pixel.y+coord[1];
if (!isEmpty(x,y)) {
var otherPixel = pixelMap[x][y];
breakPixel(otherPixel);
}
}
},
movable: false,
},
elements.mixer = {
color: "#F0F0F0",
behavior: behaviors.WALL,
category: "machines",
tick: function(pixel){
pixel.mixList = [];
for (var i = 0; i < squareCoords.length; i++) {
var coord = squareCoords[i];
var x = pixel.x+coord[0];
var y = pixel.y+coord[1];
if (!isEmpty(x,y)) {
var otherPixel = pixelMap[x][y];
pixel.mixList.push(otherPixel);
}
}
for (var i = 0; i < pixel.mixList.length; i++) {
var pixel1 = pixel.mixList[Math.floor(Math.random()*pixel.mixList.length)];
var pixel2 = pixel.mixList[Math.floor(Math.random()*pixel.mixList.length)];
swapPixels(pixel1,pixel2);
pixel.mixList.splice(pixel.mixList.indexOf(pixel1),1);
pixel.mixList.splice(pixel.mixList.indexOf(pixel2),1);
if (elements[pixel1.element].onMix) {
elements[pixel1.element].onMix(pixel1,pixel2);
}
if (elements[pixel2.element].onMix) {
elements[pixel2.element].onMix(pixel2,pixel1);
}
}
},
movable: false,
}

58
mods/precisionDrawing.js Normal file
View File

@ -0,0 +1,58 @@
let precisionDrawing = false
//mod made by feeshmaster
//try out debugRework.js or any other mods made by me!
document.addEventListener("keydown", (e) => {
if (e.key == "w" && precisionDrawing) {
mousePos.y -= 1
} else if (e.key == "a" && precisionDrawing) {
mousePos.x -= 1
} else if (e.key == "s" && precisionDrawing) {
mousePos.y += 1
} else if (e.key == "d" && precisionDrawing) {
mousePos.x += 1
} else if (event.key === 'X' && event.shiftKey) {
console.log("precisionMode deactivated!")
precisionDrawing = !precisionDrawing
if (!precisionDrawing) {
mousePos = {x: "not", y: "updated"}
}
}
})
setTimeout(setUpOnStart, 1000)
function setUpOnStart() {
getMousePos = (canvas, evt) => {
if (precisionDrawing) {
return mousePos;
}
// If evt.touches is defined, use the first touch
if (evt.touches) {
evt.preventDefault();
evt = evt.touches[0];
isMobile = true;
}
var rect = canvas.getBoundingClientRect();
return {
// Round to nearest pixel
x: Math.round((evt.clientX - rect.left)/pixelSize-0.5),
y: Math.round((evt.clientY - rect.top)/pixelSize-0.5)
};
}
let controlsTable = document.getElementById("controlsTable");
let row1 = document.createElement("tr");
row1.innerHTML = `<td colspan="2" style="text-align:center"><strong>Mod controls</strong></td>`;
let row2 = document.createElement("tr");
row2.innerHTML = `<td>start precision</td><td><kbd>Shift + X</kbd> or <kbd>toggle button(not released)</kbd></td>`;
let row3 = document.createElement("tr");
row3.innerHTML = `<td>move in precision</td><td><kbd>W, A, S, D/arrows</kbd> or <kbd>buttons(not released)</kbd></td>`;
// Append the rows
controlsTable.appendChild(row1);
controlsTable.appendChild(row2);
controlsTable.appendChild(row3);
}

View File

@ -22,7 +22,7 @@ var runAfterAutogenMod = "mods/runAfterAutogen2.js";
var libraryMod = "mods/code_library.js";
if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(libraryMod)) {
whenAvailable(["runAfterAutogen","libraryLoaded"], function() {
whenAvailable(["raaLoaded","libraryLoaded"], function() {
runAfterAutogen(function() {
snowAndIceCache = Object.keys(elements).filter(function(name) {
return name.endsWith("snow") || name.endsWith("ice") || name == "rime"

View File

@ -51,4 +51,6 @@ function createButtonsAndCountElements() {
}, 10);
};
runAfterAutogen(createButtonsAndCountElements);
runAfterAutogen(createButtonsAndCountElements);
raaLoaded = true;