From e1f9be1ec21eed37c775a641fa2edd0db752c65f Mon Sep 17 00:00:00 2001 From: redbirdly <155550833+redbirdly@users.noreply.github.com> Date: Sun, 25 Aug 2024 14:01:28 +0800 Subject: [PATCH 1/2] Add files via upload --- mods/planet.js | 270 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 mods/planet.js diff --git a/mods/planet.js b/mods/planet.js new file mode 100644 index 00000000..d51913a6 --- /dev/null +++ b/mods/planet.js @@ -0,0 +1,270 @@ +// Define the corrected biomes with heights +var mercuryLayers = [ + { layers: ["basalt", "iron"], height: 0.6 }, + { layers: ["nickel"], height: 0.2 }, + { layers: ["iron"], height: 0.2 } +]; + +var venusLayers = [ + { layers: ["basalt", "limestone"], height: 0.5 }, + { layers: ["sand", "ash", "clay"], height: 0.25 }, + { layers: ["tuff"], height: 0.15 }, + { layers: ["sulfur", ["basalt", "sand"]], height: 0.1 } +]; + +var earthLayers = [ + { layers: ["rock", "basalt", "tuff", "limestone"], height: 0.55 }, + { layers: ["clay", "mudstone", "clay_soil"], height: 0.3 }, + { layers: [["sand", "wet_sand", "clay"], ["grass", "gravel", "dirt"]], height: 0.15 } +]; + +var marsLayers = [ + { layers: ["iron", "nickel"], height: 0.3 }, + { layers: ["iron", "nickel", "rust"], height: 0.15 }, + { layers: ["iron", "nickel", "rust", "rust"], height: 0.15 }, + { layers: ["rust"], height: 0.4 } +]; + +function tryCreateStaticPixel(pixelType, x, y) { + var staticPixelType = "static_" + pixelType; + + // Check if the static version of the pixel type exists + if (!elements[staticPixelType]) { + // Create the static version of the pixel type + elements[staticPixelType] = Object.assign({}, elements[pixelType], { + behavior: behaviors.WALL, + tick: undefined + }); + } + + // Create the static pixel + tryCreatePixel(staticPixelType, x, y); +} + +function getRandomWeightedElement(weightedList) { + // Parse the input string into an array of objects with name and weight properties + const elements = weightedList.split(',').map(item => { + const [name, weight] = item.split('%'); + return { name: name.trim(), weight: parseFloat(weight) }; + }); + + // Calculate the total weight + const totalWeight = elements.reduce((total, element) => total + element.weight, 0); + + // Generate a random number between 0 and totalWeight + const randomWeight = Math.random() * totalWeight; + + // Find the element corresponding to the random weight + let cumulativeWeight = 0; + for (const element of elements) { + cumulativeWeight += element.weight; + if (randomWeight < cumulativeWeight) { + return element.name; + } + } +} + +// Function to load a script dynamically +function loadScript(url) { + var script = document.createElement("script"); + script.type = "text/javascript"; + script.src = url; + document.head.appendChild(script); +} + +function circleSimplexNoise1D(simplex, theta) { + return simplex.noise2D(Math.cos(theta * Math.PI / 180), Math.sin(theta * Math.PI / 180)); +} + +// Load the simplex-noise library +loadScript("https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.4.0/simplex-noise.min.js"); + +function getRandomElement(layer) { + if (!layer || layer.length === 0) { + return null; // Return null or handle the error case + } + return layer[Math.floor(Math.random() * layer.length)]; +} + +function generatePlanet(config, x, y, radius) { + var simplex = new SimplexNoise(); + + var centerX = x; + var centerY = y; + var planetRadius = radius; + var cloudStartRadius = planetRadius + 7; + var cloudEndRadius = planetRadius + 14; + + // Generate terrain + for (var r = 0; r <= planetRadius; r++) { + var step = 0.5; + if (r <= 50) { step = 1; } + if (r <= 20) { step = 2; } + for (var theta = 0; theta <= 360; theta += step) { + var x = Math.round(centerX + r * Math.cos(theta * Math.PI / 180)); + var y = Math.round(centerY + r * Math.sin(theta * Math.PI / 180)); + + if (x >= 0 && x < width && y >= 0 && y < height) { + var distance = Math.sqrt(Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2)); + var noise = (-Math.abs(circleSimplexNoise1D(simplex, theta * 0.7)) * 0.5) + (-Math.abs(circleSimplexNoise1D(simplex, theta * 2.5)) * 0.3); + var noisyDistance = distance - (noise * planetRadius * 0.3); + + if (noisyDistance <= planetRadius) { + // Determine the layer based on distance from center + var totalHeight = 0; + for (var i = 0; i < config.biomes.length; i++) { + totalHeight += config.biomes[i].height; + } + + var cumulativeHeight = 0; + var chosenLayer = null; + + for (var i = 0; i < config.biomes.length; i++) { + var biome = config.biomes[i]; + var layerHeight = (biome.height / totalHeight) * planetRadius; + + if (noisyDistance >= cumulativeHeight && noisyDistance < cumulativeHeight + layerHeight) { + chosenLayer = biome.layers; + + // If chosenLayer is a list of lists, pick a sublayer based on noise + if (Array.isArray(chosenLayer) && Array.isArray(chosenLayer[0])) { + var sublayerNoise = (circleSimplexNoise1D(simplex, theta) + 1) / 2; + var sublayerIndex = Math.floor(sublayerNoise * chosenLayer.length); + if (sublayerIndex < 0) { + sublayerIndex = 0; + } else if (sublayerIndex >= chosenLayer.length) { + sublayerIndex = chosenLayer.length - 1; + } + chosenLayer = chosenLayer[sublayerIndex]; + } + break; + } + + cumulativeHeight += layerHeight; + } + + var element = getRandomElement(chosenLayer); + if (element) { + tryCreateStaticPixel(element, x, y); + } + } + } + } + } + + if (config.oceanElements) { + for (var i = centerX - planetRadius; i <= centerX + planetRadius; i++) { + for (var j = centerY - planetRadius; j <= centerY + planetRadius; j++) { + if (i >= 0 && i < width && j >= 0 && j < height) { + var distanceFromCenter = Math.sqrt(Math.pow(i - centerX, 2) + Math.pow(j - centerY, 2)); + if (distanceFromCenter > planetRadius - 40 && distanceFromCenter <= planetRadius - 4) { + // Place ocean in the ring around the planet + tryCreateStaticPixel(getRandomWeightedElement(config.oceanElements), i, j); + } + } + } + } + } + + if (config.cloudElements) { + for (var r = cloudStartRadius; r <= cloudEndRadius; r++) { + var step = 1; + for (var theta = 0; theta <= 360; theta += step) { + var x = Math.round(centerX + r * Math.cos(theta * Math.PI / 180)); + var y = Math.round(centerY + r * Math.sin(theta * Math.PI / 180)); + + if (x >= 0 && x < width && y >= 0 && y < height) { + var distance = Math.sqrt(Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2)); + var cloudNoise = simplex.noise2D(x * 0.05, y * 0.05) + simplex.noise2D(x * 0.17, y * 0.17); + + // Adjust cloud density based on distance from planet + var minCloudThreshold = 0.5 + config.cloudDensityBias; // Minimum threshold closer to the planet + var maxCloudThreshold = 0.8 + config.cloudDensityBias; // Maximum threshold further from the planet + + // Interpolate threshold based on distance from planet + var t = (r - cloudStartRadius) / (cloudEndRadius - cloudStartRadius); + var threshold = minCloudThreshold + t * (maxCloudThreshold - minCloudThreshold); + + if (cloudNoise > threshold) { + tryCreateStaticPixel(getRandomWeightedElement(config.cloudElements), x, y); + } + } + } + } + } +} + + +var mercuryConfig = { + biomes: mercuryLayers, + cloudElements: "", + cloudDensityBias: 0.0 +}; + +var venusConfig = { + biomes: venusLayers, + cloudElements: "ammonia%70,acid_cloud%30", + cloudDensityBias: 0.2 +}; + +var earthConfig = { + biomes: earthLayers, + oceanElements: "salt_water%80,water%20", + cloudElements: "cloud%100", + cloudDensityBias: 0.0 +}; + +var marsConfig = { + biomes: marsLayers, + cloudElements: "", + cloudDensityBias: 0.0 +}; + + +elements.planetMercury = { + behavior: behaviors.WALL, + category: "special", + maxSize: 1, + tick: function(pixel) { + if (pixel.start === pixelTicks) { + deletePixel(pixel.x, pixel.y); + generatePlanet(mercuryConfig, pixel.x, pixel.y, 13); + } + } +}; + +elements.planetVenus = { + behavior: behaviors.WALL, + category: "special", + maxSize: 1, + tick: function(pixel) { + if (pixel.start === pixelTicks) { + deletePixel(pixel.x, pixel.y); + generatePlanet(venusConfig, pixel.x, pixel.y, 30); + } + } +}; + +elements.planetEarth = { + behavior: behaviors.WALL, + category: "special", + maxSize: 1, + tick: function(pixel) { + if (pixel.start === pixelTicks) { + deletePixel(pixel.x, pixel.y); + generatePlanet(earthConfig, pixel.x, pixel.y, 33); + } + } +}; + +elements.planetMars = { + behavior: behaviors.WALL, + category: "special", + maxSize: 1, + tick: function(pixel) { + if (pixel.start === pixelTicks) { + deletePixel(pixel.x, pixel.y); + generatePlanet(marsConfig, pixel.x, pixel.y, 20); + } + } +}; From 1c0694701b8db36e4e02c4c89c96efcf6d3d8231 Mon Sep 17 00:00:00 2001 From: redbirdly <155550833+redbirdly@users.noreply.github.com> Date: Sun, 25 Aug 2024 14:10:49 +0800 Subject: [PATCH 2/2] Add files via upload --- mods/element_UI.js | 140 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 mods/element_UI.js diff --git a/mods/element_UI.js b/mods/element_UI.js new file mode 100644 index 00000000..9ee61e0a --- /dev/null +++ b/mods/element_UI.js @@ -0,0 +1,140 @@ +// element_UI.js - Redbirdly's Mod that adds an alternative square element UI + +// Convert any html-valid color into RGB +function cssColorToRGB(color) { + const div = document.createElement('div'); + div.style.color = color; + document.body.appendChild(div); + const computedColor = window.getComputedStyle(div).color; + document.body.removeChild(div); + const rgbValues = computedColor.match(/\d+/g).map(Number); + return rgbValues; +} + +function getColorBrightness(color) { + const [r, g, b] = cssColorToRGB(color); + return (r * 299 + g * 587 + b * 114) / 1000; +} + +function createButtons(elements, inputDivId, currentCategory) { + const elementControls = document.getElementById('elementControls'); + const existingContainer = document.getElementById('grid-container'); + if (existingContainer) { + existingContainer.remove(); + } + + const container = document.createElement('div'); + container.id = 'grid-container'; + Object.assign(container.style, { + display: 'grid', + gap: '5px', + maxHeight: '280px', + overflowY: 'hidden', + overflowX: 'auto', + scrollbarColor: 'rgba(255, 255, 255, 0.25) rgba(255, 255, 255, 0.1)', + scrollbarWidth: 'thin' + }); + + const buttonNames = []; + let numButtons = 0; + let numColumns = 0; + + for (let index in elements) { + if (elements.hasOwnProperty(index) && elements[index].category !== "tools" && elements[index].category === currentCategory) { + const name = index.replace(/_/g, ' '); + numButtons++; + let color = 'gray'; + if (elements[index].color !== undefined) { + if (typeof elements[index].color === 'string') { + color = elements[index].color; + } else if (Array.isArray(elements[index].color)) { + color = elements[index].color[0]; + } + } + buttonNames.push({ name, color }); + } + } + + numColumns = Math.ceil(numButtons / 3); + container.style.gridTemplateColumns = `repeat(${numColumns}, 60px)`; + container.style.gridTemplateRows = 'repeat(3, 60px)'; + + buttonNames.forEach((buttonInfo, index) => { + const button = document.createElement('div'); + button.className = 'grid-item'; + button.style.backgroundColor = buttonInfo.color; + button.innerText = buttonInfo.name; + const brightness = getColorBrightness(buttonInfo.color); + button.style.color = brightness > 210 ? 'black' : 'white'; + Object.assign(button.style, { + width: '60px', + height: '60px', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + fontSize: '8px', + cursor: 'pointer', + border: '4px solid transparent', + borderRadius: '0px', + textAlign: 'center', + wordWrap: 'break-word', + transition: 'background-color 0.3s, color 0.3s, border 0.3s' + }); + + button.addEventListener('click', function() { + document.querySelectorAll('.grid-item').forEach(btn => { + btn.classList.remove('selected'); + btn.style.border = '4px solid transparent'; + }); + button.classList.add('selected'); + button.style.border = '4px solid white'; + currentElement = buttonInfo.name.replace(' ', '_'); + const element = elements[currentElement]; + if (element && typeof element.onSelect === 'function') { + element.onSelect(); + } + }); + + container.appendChild(button); + }); + + const inputDiv = document.createElement('div'); + inputDiv.id = inputDivId; + + elementControls.insertAdjacentElement('afterend', container); + container.insertAdjacentElement('afterend', inputDiv); + elementControls.style.display = 'none'; +} + +function getCurrentCategory() { + const categoryButtons = document.querySelectorAll('[current="true"]'); + if (categoryButtons.length === 0) { + return null; + } + return categoryButtons[0].id.replace("categoryButton-", ""); +} + +function selectCategory(category) { + if (!category) { return; } + const categoryButton = document.getElementById("categoryButton-"+category); + if (!categoryButton) { return; } + if (categoryButton.classList.contains("notify")) { + categoryButton.classList.remove("notify"); + } + const categoryDiv = document.getElementById("category-"+category); + for (let i = 0; i < categoryButton.parentNode.children.length; i++) { + const e = categoryDiv.parentNode.children[i]; + e.style.display = "none"; + document.getElementById("categoryButton-"+e.getAttribute("category")).setAttribute("current", false); + } + categoryDiv.style.display = "block"; + categoryButton.setAttribute("current", true); + createButtons(elements, 'input-div', category); +} + +const initialCategory = getCurrentCategory(); +if (initialCategory) { + selectCategory(initialCategory); +} + +selectElement("sand"); \ No newline at end of file