From b7ddc97385bcabe7ecece21898a2d8f46d2e0848 Mon Sep 17 00:00:00 2001 From: An Orbit <68935009+orbit-loona@users.noreply.github.com> Date: Mon, 5 Jan 2026 14:36:35 -0500 Subject: [PATCH 1/4] Update a_mod_by_alice.js --- mods/a_mod_by_alice.js | 65 ++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/mods/a_mod_by_alice.js b/mods/a_mod_by_alice.js index 703f08c0..9e9840e3 100644 --- a/mods/a_mod_by_alice.js +++ b/mods/a_mod_by_alice.js @@ -1466,6 +1466,7 @@ try { function createPixelReturn(elementIn,x,y) { //sugar var element = elementIn; while(element instanceof Array) { element = randomChoice(element) }; + if(pixelMap[x]?.[y] == undefined) { return {} } var newPixel = new Pixel(x, y, element); currentPixels.push(newPixel); checkUnlock(element); @@ -2214,8 +2215,8 @@ try { return thingsArray.join(", ") }; }; - function capitalizeFirstLetter(string,locale=null) { - return string[0][locale ? "toLocaleUpperCase" : "toUpperCase"](locale) + string.slice(1) + function capitalizeFirstLetter(string) { + return string[0].toUpperCase() + string.slice(1) }; //INTERFACE TO SET OTHER PIXEL PROPERTIES WHEN PLACING SPECIFIC ELEMENTS ## @@ -4568,24 +4569,28 @@ color1 and color2 spread through striped paint like dye does with itself. col } else if (Math.floor(Math.random()*100)col //console.log((pixel.x+randomMove1[0]) + " " + (pixel.y+randomMove1[1])) var newPixel = null; if(!outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1])) { - newPixel = pixelMap[pixel.x+randomMove1[0]][pixel.y+randomMove1[1]]; //newPixel is AAA + if(pixelMap[pixel.x+randomMove1[0]] !== undefined) { + newPixel = pixelMap[pixel.x+randomMove1[0]][pixel.y+randomMove1[1]]; //newPixel is AAA + } }; if(outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1]) || !reactionStealer(pixel,newPixel,"radiation")) { var randomMove2 = move2Spots[Math.floor(Math.random() * move2Spots.length)]; if(!tryMove(pixel, pixel.x+randomMove2[0], pixel.y+randomMove2[1])) { var newPixel = null; if(!outOfBounds(pixel.x+randomMove1[0],pixel.y+randomMove1[1])) { - newPixel = pixelMap[pixel.x+randomMove1[0]][pixel.y+randomMove1[1]]; //newPixel is AAA + if(pixelMap[pixel.x+randomMove1[0]] !== undefined) { + newPixel = pixelMap[pixel.x+randomMove1[0]][pixel.y+randomMove1[1]]; //newPixel is AAA + } }; if(newPixel !== null) { reactionStealer(pixel,newPixel,"radiation") }; }; @@ -9192,7 +9201,7 @@ color1 and color2 spread through striped paint like dye does with itself. col for(var i = 0; i < dyeColors.length; i++) { newLegacyFnmDye(dyeColors[i][0],dyeColors[i][1]) }; - eLists.LED = ["led_r","led_g","led_b","led"]; + eLists.LED = ["led_r","led_g","led_b"]; function newLED(abbrev,hexColor,baseColorOverrideHex=null) { if(!(hexColor.startsWith("#"))) { hexColor = "#" + hexColor }; if(baseColorOverrideHex && !(baseColorOverrideHex.startsWith("#"))) { baseColorOverrideHex = "#" + baseColorOverrideHex }; @@ -13708,7 +13717,7 @@ Pixel size (rendering only): (Use if the save looks cut o stats += "Burning"; } if (elements[currentPixel.element].hoverStat) { - stats += ""+elements[currentPixel.element].hoverStat(currentPixel)+""; + stats += ""+elements[currentPixel.element]?.hoverStat?.(currentPixel)+""; } else if (elements[currentElement].toolHoverStat) { stats += ""+elements[currentElement].toolHoverStat(currentPixel).toString().replaceAll("<","<")+""; @@ -14060,7 +14069,9 @@ Pixel size (rendering only): (Use if the save looks cut o //3. slice(1) removes empty (OOB) position at y=0 //4. indexOf(false) always shows the first matching item //5. an offset I don't understand (probably from that slice) shifts the first match to the empty spot above the first full pixel - var firstEmptyY = [...pixelMap[x].map(obj =>!obj || elements[obj.element].state == "gas"),false].slice(1).indexOf(false); + let row = pixelMap?.[x]; + if(!row) { return false }; + var firstEmptyY = [...(row.map(obj =>!obj || elements[obj.element].state == "gas")),false].slice(1).indexOf(false); if(firstEmptyY == -1) { return false; }; @@ -42225,7 +42236,7 @@ Make sure to save your command in a file if you want to add this preset again.` emptySlots = emptySlots.slice(0,2); for(var i = 0; i < emptySlots.length; i++) { var coords = emptySlots[i]; - createPixelReturn("steam",...coords).temp = pixel.temp + let n = tryCreatePixelReturn("steam",...coords); if(n) { n.temp = pixel.temp } }; changePixel(pixel,"calcium_sulfate",false); return @@ -42243,7 +42254,7 @@ Make sure to save your command in a file if you want to add this preset again.` emptySlots = emptySlots.slice(0,2); for(var i = 0; i < emptySlots.length; i++) { var coords = emptySlots[i]; - createPixelReturn("steam",...coords).temp = pixel.temp + let n = tryCreatePixelReturn("steam",...coords); if(n) { n.temp = pixel.temp } }; changePixel(pixel,"molten_calcium_sulfate",false); return @@ -44975,7 +44986,7 @@ 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; + delete elements; var max = 0; var maxElement = ""; for (var e in elements) { @@ -46005,6 +46016,12 @@ maxPixels (default 1000): Maximum amount of pixels/changes (if xSpacing and ySpa logMessage("a_mod_by_alice.js requires many other mods. Many of the elements and features added with it installed are actually added by the other mods it depends on.") logMessage('These mods are libhooktick.js, chem.js, minecraft.js, Neutronium Mod.js, fey_and_more.js, velocity.js, ketchup_mod.js, moretools.js, aChefsDream.js, nousersthings.js. They were enabled automatically') }) + isEmpty = function(x, y, ignoreBounds=false, oob=false) { + if (oob === true || outOfBounds(x,y)) { + return ignoreBounds; + } + return pixelMap[x]?.[y] === undefined; //fix failure to handle nonexistent columns + } } catch (error) { alert(`Load failed (try reloading).\nThis is likely a sporadic failure caused by inconsistencies in how mods are loaded, and will likely fix itself in a refresh or two. If it persists, then it's an issue.\nError: ${error.stack}`); console.error(error) From db59511beeeec4e48be3e1ca7b34df231db6f28b Mon Sep 17 00:00:00 2001 From: Orchid Date: Fri, 9 Jan 2026 07:48:38 -0600 Subject: [PATCH 2/4] added curve function --- mods/PRNGworldgenlib.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mods/PRNGworldgenlib.js b/mods/PRNGworldgenlib.js index 14b110ab..4317252e 100644 --- a/mods/PRNGworldgenlib.js +++ b/mods/PRNGworldgenlib.js @@ -14,6 +14,18 @@ let oreChances = { uranium: 0.805, aluminum: 1 } +function makeCurve(pos, w, dir, div = 100){ + let prevX = pos[0], prevY = pos[1]; + let res = []; + for(i = w; i >= 0; i--){ + let x2 = (dir == 1) ? pos[0]-i : pos[0]+i; + let y2 = height-((1/div)*(x2**2)); + console.log(prevX, prevY, Math.round(x2), Math.round(y2)); + res = res.concat(lineCoords(prevX, prevY, Math.round(x2), Math.round(y2), 1)); + prevX = Math.round(x2), prevY = Math.round(y2); + } + return res; +} class biome { constructor(layersArr, yLevels, properties, afterFunc = false){ this.layers = layersArr; From 066ec1b3d07b763a7881fbb7da7a4773047b166f Mon Sep 17 00:00:00 2001 From: Vito Date: Fri, 9 Jan 2026 09:57:21 -0600 Subject: [PATCH 3/4] applied curve and added beach biome --- mods/PRNGworldgenlib.js | 89 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 5 deletions(-) diff --git a/mods/PRNGworldgenlib.js b/mods/PRNGworldgenlib.js index 4317252e..32799978 100644 --- a/mods/PRNGworldgenlib.js +++ b/mods/PRNGworldgenlib.js @@ -14,23 +14,49 @@ let oreChances = { uranium: 0.805, aluminum: 1 } -function makeCurve(pos, w, dir, div = 100){ +function makeCurve(pos, w, dir, div = 200){ let prevX = pos[0], prevY = pos[1]; let res = []; for(i = w; i >= 0; i--){ let x2 = (dir == 1) ? pos[0]-i : pos[0]+i; - let y2 = height-((1/div)*(x2**2)); + let y2 = height-((1/div)*(i**2)); console.log(prevX, prevY, Math.round(x2), Math.round(y2)); res = res.concat(lineCoords(prevX, prevY, Math.round(x2), Math.round(y2), 1)); prevX = Math.round(x2), prevY = Math.round(y2); } return res; } +let structureFuncs = { + ocean: (seed)=>{ + let side = (pseudorandom(15, (seed/2**32)*62, 1) > 0.5) ? 0 : width; + let positions = makeCurve([side, 45], 90, (side == 0) ? -1 : 1, 200-(pseudorandom(82, (seed/2**32)*972, 70) - 35)); + let obj = {}; + for(let pos of positions){ + if(obj[pos[0]] != undefined){ + obj[pos[0]] = (obj[pos[0]] > pos[1]) ? obj[pos[0]] : pos[1]; + } else { + obj[pos[0]] = pos[1]; + } + } + for(let key in obj){ + for(let i = obj[key]; i > 0; i--){ + let p = getPixel(key, i); + if(p != null){ + changePixel(p, "water"); + } + //tryDelete(key, i); + } + } + + + }, +}; class biome { - constructor(layersArr, yLevels, properties, afterFunc = false){ + constructor(layersArr, yLevels, properties, afterFunc = false, genStructures = false){ this.layers = layersArr; this.yLevels = yLevels; this.vMulti = 1; + this.structures = (genStructures != false) ? [].concat(genStructures) : undefined; for(let item in properties){ this[item] = properties[item]; } @@ -126,6 +152,11 @@ class biome { if(this.afterFunc != null){ this.afterFunc(seed); } + if(this.structures != undefined){ + for(let gen of this.structures){ + gen(seed); + } + } } } let biomes = { @@ -133,6 +164,19 @@ let biomes = { desert: new biome([["rock", "rock", "rock", "gravel"], ["rock", "packed_sand","rock", "packed_sand", "sand"], ["sand"], [null, null, null, null, null, null, null, null, null, "cactus"]], [17, 26, 40, 42], {vMulti: 1.2}), savanna: new biome([["rock", "rock", "rock", "gravel"], ["dirt", "dirt", "clay_soil", "dirt", "dirt"], ["grass",null,null, null, null, null, "sapling",null,null,null,null]], [25, 38, 40], {lc: ["#6fde26", "#8eed34", "#8cdb42", "#7bd12a", "#96e81c", "#a9e64e", "#a0d94c", "#a9d63e"], wc: ["#bdab7e", "#b09c6a", "#ab996d", "#998a63", "#917959", "#877051"], vMulti: 1.5}), tundra: new biome([["rock", "rock", "rock", "gravel"], ["dirt", "dirt", "rock", "permafrost"], ["permafrost", "permafrost", "permafrost", "permafrost", "permafrost", "permafrost", "ice", "snow"], [null,null,null,null,null,"pinecone",null,null,null,null,null,null]], [25, 30, 38, 40], {temp: -15, vMulti: 2}), + beach: new biome([["rock", "rock", "rock", "gravel"], ["rock", "gravel", "sand", "sand"], ["sand"]], [10, 5, 40], {vMulti: 0.8}, (seed)=>{ + if(enabledMods.includes("mods/plants.js")){ + for(let i = 0; i < width; i++){ + if(pseudorandom(82+(i*34), (seed/2**32)*234, 1) < 0.025){ + console.log("Placing: ", i, 20); + tryCreate("banana_seed", i, 20); + } + } + + + } + }, structureFuncs.ocean), + } let seed = Math.random()*(2**32); enabledMods.forEach((item)=>{ @@ -148,14 +192,14 @@ enabledMods.forEach((item)=>{ }}); } }); -elements.PRNGgenerate = { +elements.SeedGenerate = { category: "tools", onSelect: function(){ let arr = []; let txt = shiftDown; Object.keys(biomes).forEach(function(b){arr.push(b);}); txt = (arr.length >= 7) ? true : txt; - promptInput("Leave blank to generate new seed. Your current seed is: " + seed, function(i){ + promptInput("Leave blank to generate new seed or C to keep current seed. Your current seed is: " + seed, function(i){ seed = (i != null && i.toLowerCase() == "c") ? seed : parseFloat(i) || Math.random()*(2**32); seed = seed % (2**32); if(!txt){ @@ -183,6 +227,41 @@ elements.PRNGgenerate = { }, "Enter seed:"); } } +elements.RandomGen = { + category: "tools", + onSelect: function(){ + let arr = []; + let txt = shiftDown; + Object.keys(biomes).forEach(function(b){arr.push(b);}); + txt = (arr.length >= 7) ? true : txt; + seed = Math.random()*(2**32); + //seed %= 2**32; + if(txt){ + let str = ""; + for(let key in biomes){ + str += `${key}, `; + } + str = str.replace(/^,|,$/g, ''); + promptInput("Enter the name of a biome to generate (caps-insensetive)\nBiomes available: \n" + str, function(inp){ + let choice = inp.toLowerCase(); + if(!arr.includes(choice)){ + promptText("Invalid selection."); + selectElement("dirt"); + } else { + biomes[choice].generate(seed); + selectElement("dirt"); + + } + }, "Enter Biome Name: "); + + } else { + promptChoose("", arr, (choice)=>{ + biomes[choice].generate(seed); + selectElement("dirt"); + }, "Biome Selection"); + } + }, +} elements.view_seed = { category: "tools", onSelect: function(){ From 3fdbc72e846774411500cbcc05b95e0028a4150a Mon Sep 17 00:00:00 2001 From: Orchid Date: Fri, 9 Jan 2026 19:52:45 -0600 Subject: [PATCH 4/4] added pyramids to finalize the new version --- mods/PRNGworldgenlib.js | 95 +++++++++++++++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 17 deletions(-) diff --git a/mods/PRNGworldgenlib.js b/mods/PRNGworldgenlib.js index 32799978..4797580c 100644 --- a/mods/PRNGworldgenlib.js +++ b/mods/PRNGworldgenlib.js @@ -1,4 +1,4 @@ -/*Version 1.1.0 Pseudorandom world generator*/ +/*Version 1.2.0 Pseudorandom world generator*/ function pseudorandom(key, num, max = 1){ return (Math.log(key)*(num*Math.log(1625.4986772154357))) % max; }; @@ -20,12 +20,36 @@ function makeCurve(pos, w, dir, div = 200){ for(i = w; i >= 0; i--){ let x2 = (dir == 1) ? pos[0]-i : pos[0]+i; let y2 = height-((1/div)*(i**2)); - console.log(prevX, prevY, Math.round(x2), Math.round(y2)); res = res.concat(lineCoords(prevX, prevY, Math.round(x2), Math.round(y2), 1)); prevX = Math.round(x2), prevY = Math.round(y2); } return res; } + +elements.sandstone = { + category: "solids", + color: ["#a89f67", "#b89c6b", "#bbad68"], + behavior: behaviors.SOLID, + breakInto: "sand", + tempHigh: 1700, + stateHigh: "molten_glass", +}; + +elements.packed_sand.tempHigh = 300; +elements.packed_sand.stateHigh = "sandstone"; + +function drawLine(elem,x1,y1,x2,y2, replace = null){ + let coords = lineCoords(Math.round(x1),Math.round(y1),Math.round(x2),Math.round(y2)); + for(let pos of coords){ + let res = tryCreate(elem, pos[0], pos[1]); + if(replace != null && res == null){ + let pixel = getPixel(pos[0], pos[1]); + if(pixel != null && replace.includes(pixel.element)){ + changePixel(pixel, elem); + } + } + } +} let structureFuncs = { ocean: (seed)=>{ let side = (pseudorandom(15, (seed/2**32)*62, 1) > 0.5) ? 0 : width; @@ -50,13 +74,32 @@ let structureFuncs = { }, + pyramid: (seed)=>{ + + if(pseudorandom(232, 4564*(seed/2**32), 1) < 0.25){ + let x = pseudorandom(531, 9834*(seed/2**32), width); + let h = pseudorandom(659, 2342*(seed/2**32), 10) + 20; + let hwidth = h*Math.atan(0.78539816); + let num = 0; + for(let i = x - hwidth; i < x + hwidth; i++){ + let y = (height-35)-(h); + drawLine("sandstone", i, height-35, x, y, ["sand", "cactus"]); + num++; + if(i == x){ + num = 0; + }; + } + } + }, }; class biome { - constructor(layersArr, yLevels, properties, afterFunc = false, genStructures = false){ + constructor(layersArr, yLevels, properties, afterFunc = false, genStructures = false, sp = false){ this.layers = layersArr; this.yLevels = yLevels; this.vMulti = 1; this.structures = (genStructures != false) ? [].concat(genStructures) : undefined; + this.afterFunc = (afterFunc != false) ? afterFunc : undefined; + this.sPriority = sp; for(let item in properties){ this[item] = properties[item]; } @@ -64,6 +107,13 @@ class biome { autoResizeCanvas(); if(!paused){togglePause();} let fraction = seed/(2**32); + if(this.sPriority){ + if(this.structures != undefined){ + for(let gen of this.structures){ + gen(seed); + } + } + } for(let level of this.yLevels){ for(let x = 0; x <= width+2; x++){ //console.log(x); @@ -106,6 +156,11 @@ class biome { } } } + if(this.structures != undefined){ + for(let gen of this.structures){ + gen(seed); + } + } this.generateOreVeins(seed, this.vMulti); }; } @@ -152,29 +207,35 @@ class biome { if(this.afterFunc != null){ this.afterFunc(seed); } - if(this.structures != undefined){ - for(let gen of this.structures){ - gen(seed); - } - } + } } let biomes = { plains: new biome([["rock", "rock", "rock", "gravel"], ["dirt", "dirt", "dirt", "dirt", "mud", "gravel"], ["grass","flower_seed","grass","grass","grass","grass","sapling","grass","grass","grass","grass","grass","grass","grass","grass"]], [25, 38, 40]), - desert: new biome([["rock", "rock", "rock", "gravel"], ["rock", "packed_sand","rock", "packed_sand", "sand"], ["sand"], [null, null, null, null, null, null, null, null, null, "cactus"]], [17, 26, 40, 42], {vMulti: 1.2}), + desert: new biome([["rock", "rock", "rock", "gravel"], ["rock", "packed_sand","rock", "packed_sand", "sand"], ["sand"], [null, null, null, null, null, null, null, null, null, "cactus"]], [17, 26, 40, 42], {vMulti: 1.2}, false, structureFuncs.pyramid, true), savanna: new biome([["rock", "rock", "rock", "gravel"], ["dirt", "dirt", "clay_soil", "dirt", "dirt"], ["grass",null,null, null, null, null, "sapling",null,null,null,null]], [25, 38, 40], {lc: ["#6fde26", "#8eed34", "#8cdb42", "#7bd12a", "#96e81c", "#a9e64e", "#a0d94c", "#a9d63e"], wc: ["#bdab7e", "#b09c6a", "#ab996d", "#998a63", "#917959", "#877051"], vMulti: 1.5}), tundra: new biome([["rock", "rock", "rock", "gravel"], ["dirt", "dirt", "rock", "permafrost"], ["permafrost", "permafrost", "permafrost", "permafrost", "permafrost", "permafrost", "ice", "snow"], [null,null,null,null,null,"pinecone",null,null,null,null,null,null]], [25, 30, 38, 40], {temp: -15, vMulti: 2}), - beach: new biome([["rock", "rock", "rock", "gravel"], ["rock", "gravel", "sand", "sand"], ["sand"]], [10, 5, 40], {vMulti: 0.8}, (seed)=>{ - if(enabledMods.includes("mods/plants.js")){ + beach: new biome([["rock", "rock", "rock", "gravel"], ["rock", "gravel", "sand", "sand"], ["sand"]], [7, 13, 35], {vMulti: 0.8}, (seed)=>{ + dependOn("plants.js", ()=>{ for(let i = 0; i < width; i++){ - if(pseudorandom(82+(i*34), (seed/2**32)*234, 1) < 0.025){ - console.log("Placing: ", i, 20); - tryCreate("banana_seed", i, 20); + console.log(pseudorandom((i*34), (seed/2**32)*234, 1)); + if(pseudorandom((i*34), (seed/2**32)*234, 1) < 0.035){ + let c = true; + let np = getPixel(i, 20); + let ny = 21; + while(np == null){ + np = getPixel(i, ny); + if(np != null && np.element == "water"){ + c = false; + }; + ny++; + } + if(c){ + tryCreate("banana_seed", i, 20); + } } } - - - } + }, false); }, structureFuncs.ocean), }