Merge pull request #783 from redbirdly/main
This commit is contained in:
commit
c29052185d
|
|
@ -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");
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue