Merge branch 'main' of https://github.com/R74nCom/sandboxels
This commit is contained in:
commit
4e9391d2c1
|
|
@ -1,3 +1,7 @@
|
||||||
|
// TypeScript integration for Sandboxels modding
|
||||||
|
// Enables function autocomplete & element definition hints
|
||||||
|
/// <reference path="./sandboxels-types.d.ts" />
|
||||||
|
// Get the file here: https://github.com/Cube14yt/sandboxels-types
|
||||||
// Changelog
|
// Changelog
|
||||||
// Starts at version 3
|
// Starts at version 3
|
||||||
|
|
||||||
|
|
@ -21,8 +25,15 @@ Machines: Robot, Adjustable heater/cooler
|
||||||
|
|
||||||
Bug Fixes
|
Bug Fixes
|
||||||
Fixed compatibility issue with nousersthings.js
|
Fixed compatibility issue with nousersthings.js
|
||||||
*/
|
|
||||||
|
|
||||||
|
V4
|
||||||
|
Machines: Paper filter, Indestructable filter, and Note block
|
||||||
|
Life: Cacao Plants (seed, stem, fruit)
|
||||||
|
Tools: Polish
|
||||||
|
Extras: 2 ways to make an element with no name
|
||||||
|
Special: Black hole
|
||||||
|
Building Materials: Roman concrete/cement
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
elements.button = {
|
elements.button = {
|
||||||
|
|
@ -1545,6 +1556,7 @@ function tryJump(headPixel) {
|
||||||
elements.robot_head = {
|
elements.robot_head = {
|
||||||
color: "#d9d9d9",
|
color: "#d9d9d9",
|
||||||
category: "machines",
|
category: "machines",
|
||||||
|
state: "solid",
|
||||||
tick(pixel) {
|
tick(pixel) {
|
||||||
const body = getPixel(pixel.x, pixel.y + 1);
|
const body = getPixel(pixel.x, pixel.y + 1);
|
||||||
|
|
||||||
|
|
@ -1583,6 +1595,7 @@ elements.robot_head = {
|
||||||
elements.robot_body = {
|
elements.robot_body = {
|
||||||
color: "#b1b1b1",
|
color: "#b1b1b1",
|
||||||
category: "machines",
|
category: "machines",
|
||||||
|
state: "solid",
|
||||||
tick(pixel) {
|
tick(pixel) {
|
||||||
const head = getPixel(pixel.x, pixel.y - 1);
|
const head = getPixel(pixel.x, pixel.y - 1);
|
||||||
|
|
||||||
|
|
@ -1608,6 +1621,7 @@ elements.robot_body = {
|
||||||
elements.robot = {
|
elements.robot = {
|
||||||
color: "#b1b1b1",
|
color: "#b1b1b1",
|
||||||
category: "machines",
|
category: "machines",
|
||||||
|
state: "solid",
|
||||||
onSelect() {
|
onSelect() {
|
||||||
promptChoose(
|
promptChoose(
|
||||||
"Choose robot mode",
|
"Choose robot mode",
|
||||||
|
|
@ -1663,6 +1677,7 @@ elements.broken_adjustable_heater = {
|
||||||
category: "extras",
|
category: "extras",
|
||||||
insulate: true,
|
insulate: true,
|
||||||
behavior: behaviors.WALL,
|
behavior: behaviors.WALL,
|
||||||
|
|
||||||
onSelect() {
|
onSelect() {
|
||||||
promptInput(
|
promptInput(
|
||||||
"Select the temperature you want to adjust to",
|
"Select the temperature you want to adjust to",
|
||||||
|
|
@ -1730,24 +1745,7 @@ elements.adjustable_heater = {
|
||||||
} else if (current_pixel.temp > adjusted_temp) {
|
} else if (current_pixel.temp > adjusted_temp) {
|
||||||
current_pixel.temp = Math.max(current_pixel.temp - heatAmount, adjusted_temp);
|
current_pixel.temp = Math.max(current_pixel.temp - heatAmount, adjusted_temp);
|
||||||
}
|
}
|
||||||
|
pixelTempCheck(current_pixel)
|
||||||
// Phase change check (forces melting/boiling/etc.)
|
|
||||||
let elemDef = elements[current_pixel.element];
|
|
||||||
if (elemDef) {
|
|
||||||
// Too hot for current state → change to high state
|
|
||||||
if (typeof elemDef.tempHigh === "number" &&
|
|
||||||
current_pixel.temp >= elemDef.tempHigh &&
|
|
||||||
elemDef.stateHigh) {
|
|
||||||
changePixel(current_pixel, elemDef.stateHigh);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Too cold for current state → change to low state
|
|
||||||
if (typeof elemDef.tempLow === "number" &&
|
|
||||||
current_pixel.temp <= elemDef.tempLow &&
|
|
||||||
elemDef.stateLow) {
|
|
||||||
changePixel(current_pixel, elemDef.stateLow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1831,27 +1829,633 @@ elements.adjustable_cooler = {
|
||||||
current_pixel.temp = Math.min(current_pixel.temp + coolAmount, adjusted_cool_temp);
|
current_pixel.temp = Math.min(current_pixel.temp + coolAmount, adjusted_cool_temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phase change check (forces melting/freezing/etc.)
|
pixelTempCheck(current_pixel)
|
||||||
let elemDef = elements[current_pixel.element];
|
|
||||||
if (elemDef) {
|
|
||||||
// Too hot → change to high state
|
|
||||||
if (typeof elemDef.tempHigh === "number" &&
|
|
||||||
current_pixel.temp >= elemDef.tempHigh &&
|
|
||||||
elemDef.stateHigh) {
|
|
||||||
changePixel(current_pixel, elemDef.stateHigh);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Too cold → change to low state
|
|
||||||
if (typeof elemDef.tempLow === "number" &&
|
|
||||||
current_pixel.temp <= elemDef.tempLow &&
|
|
||||||
elemDef.stateLow) {
|
|
||||||
changePixel(current_pixel, elemDef.stateLow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let polishedList = new Set()
|
||||||
|
elements.polish = {
|
||||||
|
category: "tools",
|
||||||
|
color: ["#a0dff0", "#c0e8f8", "#e0f5ff"],
|
||||||
|
tool(pixel) {
|
||||||
|
let element = pixel.element
|
||||||
|
if ((elements[pixel.element].colorPattern && !polishedList.has(`${pixel.x}, ${pixel.y}`)) || shiftDown) {
|
||||||
|
deletePixel(pixel.x, pixel.y)
|
||||||
|
createPixel(element, pixel.x, pixel.y)
|
||||||
|
polishedList.add(`${pixel.x}, ${pixel.y}`)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onUnselect() {
|
||||||
|
polishedList.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elements[" "] = {
|
||||||
|
category: "extras",
|
||||||
|
onSelect() {
|
||||||
|
logMessage("This Element has weird properties since its a space ' '")
|
||||||
|
},
|
||||||
|
alias: "space"
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.paper_filter = {
|
||||||
|
desc: "Filters solids from liquids",
|
||||||
|
color: "#ececec",
|
||||||
|
behavior: behaviors.WALL,
|
||||||
|
reactions: {
|
||||||
|
"light": { stain1: "#ebdfa7" },
|
||||||
|
"oxygen": { stain1: "#ebdfa7" }
|
||||||
|
},
|
||||||
|
tempHigh: 248,
|
||||||
|
stateHigh: ["fire", "fire", "fire", "fire", "fire", "ash"],
|
||||||
|
burn: 70,
|
||||||
|
burnTime: 300,
|
||||||
|
burnInto: ["fire", "fire", "fire", "fire", "fire", "ash"],
|
||||||
|
category: "machines",
|
||||||
|
density: 1201,
|
||||||
|
breakInto: "confetti",
|
||||||
|
breakIntoColor: ["#ffffff", "#e6e6e6", "#dbdbdb"],
|
||||||
|
tick(pixel) {
|
||||||
|
let upPixel = getPixel(pixel.x, pixel.y - 1)
|
||||||
|
|
||||||
|
if (upPixel && elements[upPixel.element].state == "liquid" && !pixel.con) {
|
||||||
|
deletePixel(pixel.x, pixel.y - 1)
|
||||||
|
pixel.con = upPixel
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upPixel && (upPixel.element === "paper_filter" || upPixel.element === "indestructable_filter") && upPixel.con && !pixel.con) {
|
||||||
|
let liquid = upPixel.con
|
||||||
|
let viscMove = true
|
||||||
|
|
||||||
|
if (elements[liquid.element].viscosity) {
|
||||||
|
viscMove = (Math.random() * 100) < (100 / Math.pow(elements[liquid.element].viscosity, 0.5))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viscMove) {
|
||||||
|
pixel.con = liquid
|
||||||
|
delete upPixel.con
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEmpty(pixel.x, pixel.y + 1) && !outOfBounds(pixel.x, pixel.y + 1) && pixel.con) {
|
||||||
|
let liquid = pixel.con
|
||||||
|
let viscExit = true
|
||||||
|
|
||||||
|
if (elements[liquid.element].viscosity) {
|
||||||
|
viscExit = (Math.random() * 100) < (100 / Math.pow(elements[liquid.element].viscosity, 0.5))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viscExit) {
|
||||||
|
createPixel(liquid.element, pixel.x, pixel.y + 1)
|
||||||
|
delete pixel.con
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.indestructable_filter = {
|
||||||
|
desc: "Filters solids from liquids",
|
||||||
|
color: "#aaaaaa",
|
||||||
|
behavior: behaviors.WALL,
|
||||||
|
category: "machines",
|
||||||
|
state: "solid",
|
||||||
|
movable: false,
|
||||||
|
tick(pixel) {
|
||||||
|
let upPixel = getPixel(pixel.x, pixel.y - 1)
|
||||||
|
let belowPixel = getPixel(pixel.x, pixel.y + 1)
|
||||||
|
|
||||||
|
if (upPixel && elements[upPixel.element].state == "liquid" && !pixel.con) {
|
||||||
|
deletePixel(pixel.x, pixel.y - 1)
|
||||||
|
pixel.con = upPixel
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upPixel && (upPixel.element === "indestructable_filter" || upPixel.element === "paper_filter") && upPixel.con && !pixel.con) {
|
||||||
|
let liquid = upPixel.con
|
||||||
|
let viscMove = true
|
||||||
|
|
||||||
|
if (elements[liquid.element].viscosity) {
|
||||||
|
viscMove = (Math.random() * 100) < (100 / Math.pow(elements[liquid.element].viscosity, 0.5))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viscMove) {
|
||||||
|
pixel.con = liquid
|
||||||
|
delete upPixel.con
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEmpty(pixel.x, pixel.y + 1) && !outOfBounds(pixel.x, pixel.y + 1) && pixel.con) {
|
||||||
|
let liquid = pixel.con
|
||||||
|
let viscExit = true
|
||||||
|
|
||||||
|
if (elements[liquid.element].viscosity) {
|
||||||
|
viscExit = (Math.random() * 100) < (100 / Math.pow(elements[liquid.element].viscosity, 0.5))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viscExit) {
|
||||||
|
createPixel(liquid.element, pixel.x, pixel.y + 1)
|
||||||
|
delete pixel.con
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let black_hole_expand = false
|
||||||
|
elements.black_hole = {
|
||||||
|
color: "#111111",
|
||||||
|
hardness: 1,
|
||||||
|
category: "special",
|
||||||
|
properties: {
|
||||||
|
absorbed: 0
|
||||||
|
},
|
||||||
|
renderer: function (pixel, ctx) {
|
||||||
|
if (!viewInfo[view].colorEffects) { drawDefault(ctx, pixel); return }
|
||||||
|
renderPresets.HEATGLOW(pixel, ctx);
|
||||||
|
if (pixel.alpha === 0) return;
|
||||||
|
|
||||||
|
let edge = false;
|
||||||
|
pixel.edge = false;
|
||||||
|
pixel.color = "#111111";
|
||||||
|
|
||||||
|
for (var i = 0; i < adjacentCoords.length; i++) {
|
||||||
|
var coords = adjacentCoords[i];
|
||||||
|
var x = pixel.x + coords[0];
|
||||||
|
var y = pixel.y + coords[1];
|
||||||
|
if (!outOfBounds(x, y)) {
|
||||||
|
let neighbor = getPixel(x, y);
|
||||||
|
if (!neighbor || elements[neighbor.element].movable !== elements[pixel.element].movable) {
|
||||||
|
edge = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (edge) { pixel.color = "#ffae00"; pixel.edge = true }
|
||||||
|
},
|
||||||
|
tick(pixel) {
|
||||||
|
// Glow effect
|
||||||
|
if (pixel.edge) {
|
||||||
|
pixel.glow = true;
|
||||||
|
if (enabledMods.includes("mods/glow.js")) {
|
||||||
|
pixel.emit = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pixel.glow = false;
|
||||||
|
if (enabledMods.includes("mods/glow.js")) {
|
||||||
|
pixel.emit = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Suction physics
|
||||||
|
let radius = 20; // how far the suction reaches
|
||||||
|
for (let dx = -radius; dx <= radius; dx++) {
|
||||||
|
for (let dy = -radius; dy <= radius; dy++) {
|
||||||
|
if (dx === 0 && dy === 0) continue;
|
||||||
|
|
||||||
|
let x = pixel.x + dx;
|
||||||
|
let y = pixel.y + dy;
|
||||||
|
|
||||||
|
if (!outOfBounds(x, y)) {
|
||||||
|
let other = getPixel(x, y);
|
||||||
|
if (other && other !== pixel) {
|
||||||
|
let elemDef = elements[other.element];
|
||||||
|
|
||||||
|
// Skip if indestructible
|
||||||
|
if (elemDef.hardness === 1) continue;
|
||||||
|
|
||||||
|
// Distance to black hole
|
||||||
|
let dist = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (dist <= radius) {
|
||||||
|
// Suction chance: closer = stronger pull
|
||||||
|
let chance = 1 / dist;
|
||||||
|
if (Math.random() < chance) {
|
||||||
|
let stepX = Math.sign(pixel.x - x);
|
||||||
|
let stepY = Math.sign(pixel.y - y);
|
||||||
|
|
||||||
|
let newX = x + stepX;
|
||||||
|
let newY = y + stepY;
|
||||||
|
|
||||||
|
if (isEmpty(newX, newY) && !outOfBounds(newX, newY)) {
|
||||||
|
movePixel(other, newX, newY);
|
||||||
|
}
|
||||||
|
else if (dist <= 1.5) {
|
||||||
|
deletePixel(x, y); // absorb it
|
||||||
|
pixel.absorbed++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (black_hole_expand) {
|
||||||
|
for (var i = 0; i < adjacentCoords.length; i++) {
|
||||||
|
var x = pixel.x + adjacentCoords[i][0];
|
||||||
|
var y = pixel.y + adjacentCoords[i][1];
|
||||||
|
if (pixel.absorbed >= 30 && isEmpty(x, y)) {
|
||||||
|
createPixel("black_hole", x, y)
|
||||||
|
pixel.absorbed = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
forceSaveColor: true,
|
||||||
|
onSelect() {
|
||||||
|
promptChoose(
|
||||||
|
"Do you want the black hole to grow?",
|
||||||
|
["Yes", "No"],
|
||||||
|
(choice) => {
|
||||||
|
if (!choice) {
|
||||||
|
choice = false
|
||||||
|
}
|
||||||
|
if (choice == "Yes") {
|
||||||
|
black_hole_expand = true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
black_hole_expand = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
elements.cacao_fruit = {
|
||||||
|
color: "#854700",
|
||||||
|
behavior: [
|
||||||
|
"XX|ST:cacao_stem|XX",
|
||||||
|
"ST:cacao_stem|XX|ST:cacao_stem",
|
||||||
|
"XX|ST:cacao_stem AND M1|XX"
|
||||||
|
],
|
||||||
|
isFood: true,
|
||||||
|
burn: 10,
|
||||||
|
burnTime: 100,
|
||||||
|
burnInto: "ash",
|
||||||
|
breakInto: "cacao_bean",
|
||||||
|
category: "food",
|
||||||
|
state: "solid",
|
||||||
|
density: 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.cacao_bean = {
|
||||||
|
color: "#ffe7ba",
|
||||||
|
isFood: true,
|
||||||
|
behavior: [
|
||||||
|
"XX|XX|XX",
|
||||||
|
"XX|XX|XX",
|
||||||
|
"M2%10|M1|M2%10"
|
||||||
|
],
|
||||||
|
tempHigh: 100,
|
||||||
|
stateHigh: "dried_cacao_bean",
|
||||||
|
onStateHigh(pixel) { releaseElement(pixel, "steam") },
|
||||||
|
state: "solid",
|
||||||
|
category: "food",
|
||||||
|
density: 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.dried_cacao_bean = {
|
||||||
|
color: "#61321e",
|
||||||
|
behavior: behaviors.POWDER,
|
||||||
|
reactions: {
|
||||||
|
"sugar_water": { elem2: "melted_chocolate", tempMin: 65 },
|
||||||
|
"water": { elem2: "melted_chocolate", tempMin: 65 }
|
||||||
|
},
|
||||||
|
tempHigh: 400,
|
||||||
|
stateHigh: "ash",
|
||||||
|
isFood: true,
|
||||||
|
category: "food",
|
||||||
|
state: "solid",
|
||||||
|
density: 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.coffee_bean.reactions.sugar_water = { elem2: "coffee", tempMin: 80 }
|
||||||
|
elements.coffee.reactions.sugar_water = { elem2: "coffee", tempMin: 70, chance: 0.2 }
|
||||||
|
elements.coffee_ground.reactions.sugar_water = elements.coffee_ground.reactions.water
|
||||||
|
|
||||||
|
elements._ = {
|
||||||
|
category: "extras",
|
||||||
|
onSelect() {
|
||||||
|
logMessage("Another way to make an element with no name \"_\"")
|
||||||
|
},
|
||||||
|
alias: ["underscore"]
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.cacao_seed = {
|
||||||
|
color: "#8b3f00",
|
||||||
|
behavior: behaviors.STURDYPOWDER,
|
||||||
|
cooldown: defaultCooldown,
|
||||||
|
category: "life",
|
||||||
|
tempHigh: 400,
|
||||||
|
stateHigh: "fire",
|
||||||
|
tempLow: -2,
|
||||||
|
stateLow: "frozen_plant",
|
||||||
|
burn: 50,
|
||||||
|
burnTime: 20,
|
||||||
|
state: "solid",
|
||||||
|
tick(pixel) {
|
||||||
|
let belowPixel = getPixel(pixel.x, pixel.y + 1)
|
||||||
|
if ((!isEmpty(pixel.x, pixel.y + 1) && belowPixel) || outOfBounds(pixel.x, pixel.y + 1) && Math.random() <= 0.005) {
|
||||||
|
changePixel(pixel, "cacao_stem")
|
||||||
|
pixel.stage = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.cacao_stem = {
|
||||||
|
color: "#916a00",
|
||||||
|
renderer: renderPresets.WOODCHAR,
|
||||||
|
movable: false,
|
||||||
|
tempHigh: 100,
|
||||||
|
stateHigh: "wood",
|
||||||
|
tempLow: -30,
|
||||||
|
stateLow: "wood",
|
||||||
|
category: "life",
|
||||||
|
burn: 2,
|
||||||
|
burnTime: 300,
|
||||||
|
burnInto: ["sap", "ember", "charcoal", "smoke"],
|
||||||
|
state: "solid",
|
||||||
|
density: 1500,
|
||||||
|
hardness: 0.15,
|
||||||
|
breakInto: ["sap", "sawdust"],
|
||||||
|
seed: "cacao_seed",
|
||||||
|
forceSaveColor: true,
|
||||||
|
stateHighColorMultiplier: 0.95,
|
||||||
|
onPlace(pixel) {
|
||||||
|
pixel.stage = 1
|
||||||
|
},
|
||||||
|
hoverStat(pixel) {
|
||||||
|
if (pixel.stage) return pixel.stage;
|
||||||
|
else return 0;
|
||||||
|
},
|
||||||
|
tick(pixel) {
|
||||||
|
// 1 = trunk
|
||||||
|
// 2 = spread
|
||||||
|
// 3 = stop
|
||||||
|
if (pixel.stage === 1 && isEmpty(pixel.x, pixel.y - 1) && Math.random() <= 0.05) {
|
||||||
|
tryMove(pixel, pixel.x, pixel.y - 1, "cacao_stem")
|
||||||
|
let oldPixel = getPixel(pixel.x, pixel.y + 1)
|
||||||
|
delete oldPixel.stage
|
||||||
|
if (Math.random() <= 0.3) {
|
||||||
|
pixel.stage = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pixel.stage === 2) {
|
||||||
|
let rand = Math.random()
|
||||||
|
let nx;
|
||||||
|
if (rand < 0.4) {
|
||||||
|
nx = 1
|
||||||
|
}
|
||||||
|
else if (rand < 0.8) {
|
||||||
|
nx = -1
|
||||||
|
}
|
||||||
|
else nx = 0;
|
||||||
|
if (isEmpty(pixel.x + nx, pixel.y - 1) && Math.random() <= 0.05) {
|
||||||
|
createPixel(["cacao_stem", "plant"], pixel.x + nx, pixel.y - 1)
|
||||||
|
newPixel = getPixel(pixel.x + nx, pixel.y - 1)
|
||||||
|
if (Math.random() <= 0.2) {
|
||||||
|
newPixel.stage = 3
|
||||||
|
}
|
||||||
|
else newPixel.stage = 2;
|
||||||
|
}
|
||||||
|
if (!isEmpty(pixel.x + 1, pixel.y - 1) && !isEmpty(pixel.x, pixel.y - 1) && !isEmpty(pixel.x - 1, pixel.y - 1) && Math.random() <= 0.005) {
|
||||||
|
shuffleArray(adjacentCoordsShuffle)
|
||||||
|
for (var i = 0; i < adjacentCoordsShuffle.length; i++) {
|
||||||
|
var x = pixel.x + adjacentCoordsShuffle[i][0];
|
||||||
|
var y = pixel.y + adjacentCoordsShuffle[i][1];
|
||||||
|
if (isEmpty(x, y) && !pixel.fruitMade) {
|
||||||
|
createPixel("cacao_fruit", x, y)
|
||||||
|
pixel.fruitMade = true
|
||||||
|
pixel.fruitCoordsx = x
|
||||||
|
pixel.fruitCoordsy = y
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pixel.fruitCoordsx && pixel.fruitCoordsy) {
|
||||||
|
if (getPixel(pixel.fruitCoordsx, pixel.fruitCoordsy) && getPixel(pixel.fruitCoordsx, pixel.fruitCoordsy).element === "cacao_fruit") return;
|
||||||
|
pixel.fruitMade = false
|
||||||
|
delete pixel.fruitCoordsx
|
||||||
|
delete pixel.fruitCoordsy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- audio setup ---
|
||||||
|
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||||
|
|
||||||
|
function playNote(frequency, duration = 1, type = "sine", volume = 0.1) {
|
||||||
|
if (!Number.isFinite(frequency)) {
|
||||||
|
console.error("Invalid frequency:", frequency);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const osc = audioCtx.createOscillator();
|
||||||
|
const gain = audioCtx.createGain();
|
||||||
|
|
||||||
|
osc.type = type;
|
||||||
|
osc.frequency.value = frequency;
|
||||||
|
|
||||||
|
gain.gain.setValueAtTime(volume, audioCtx.currentTime);
|
||||||
|
osc.connect(gain);
|
||||||
|
gain.connect(audioCtx.destination);
|
||||||
|
|
||||||
|
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + duration);
|
||||||
|
|
||||||
|
osc.start();
|
||||||
|
osc.stop(audioCtx.currentTime + duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const pianoFrequencies = {
|
||||||
|
"A0": 27.500, "A#0": 29.135, "BB0": 29.135, "B0": 30.868,
|
||||||
|
"C1": 32.703, "C#1": 34.648, "DB1": 34.648, "D1": 36.708,
|
||||||
|
"D#1": 38.891, "EB1": 38.891, "E1": 41.203, "F1": 43.654,
|
||||||
|
"F#1": 46.249, "GB1": 46.249, "G1": 48.999, "G#1": 51.913,
|
||||||
|
"AB1": 51.913, "A1": 55.000, "A#1": 58.270, "BB1": 58.270,
|
||||||
|
"B1": 61.735,
|
||||||
|
|
||||||
|
"C2": 65.406, "C#2": 69.296, "DB2": 69.296, "D2": 73.416,
|
||||||
|
"D#2": 77.782, "EB2": 77.782, "E2": 82.407, "F2": 87.307,
|
||||||
|
"F#2": 92.499, "GB2": 92.499, "G2": 97.999, "G#2": 103.826,
|
||||||
|
"AB2": 103.826, "A2": 110.000, "A#2": 116.541, "BB2": 116.541,
|
||||||
|
"B2": 123.471,
|
||||||
|
|
||||||
|
"C3": 130.813, "C#3": 138.591, "DB3": 138.591, "D3": 146.832,
|
||||||
|
"D#3": 155.563, "EB3": 155.563, "E3": 164.814, "F3": 174.614,
|
||||||
|
"F#3": 184.997, "GB3": 184.997, "G3": 195.998, "G#3": 207.652,
|
||||||
|
"AB3": 207.652, "A3": 220.000, "A#3": 233.082, "BB3": 233.082,
|
||||||
|
"B3": 246.942,
|
||||||
|
|
||||||
|
"C4": 261.626, "C#4": 277.183, "DB4": 277.183, "D4": 293.665,
|
||||||
|
"D#4": 311.127, "EB4": 311.127, "E4": 329.628, "F4": 349.228,
|
||||||
|
"F#4": 369.994, "GB4": 369.994, "G4": 391.995, "G#4": 415.305,
|
||||||
|
"AB4": 415.305, "A4": 440.000, "A#4": 466.164, "BB4": 466.164,
|
||||||
|
"B4": 493.883,
|
||||||
|
|
||||||
|
"C5": 523.251, "C#5": 554.365, "DB5": 554.365, "D5": 587.330,
|
||||||
|
"D#5": 622.254, "EB5": 622.254, "E5": 659.255, "F5": 698.456,
|
||||||
|
"F#5": 739.989, "GB5": 739.989, "G5": 783.991, "G#5": 830.609,
|
||||||
|
"AB5": 830.609, "A5": 880.000, "A#5": 932.328, "BB5": 932.328,
|
||||||
|
"B5": 987.767,
|
||||||
|
|
||||||
|
"C6": 1046.502, "C#6": 1108.731, "DB6": 1108.731, "D6": 1174.659,
|
||||||
|
"D#6": 1244.508, "EB6": 1244.508, "E6": 1318.510, "F6": 1396.913,
|
||||||
|
"F#6": 1479.978, "GB6": 1479.978, "G6": 1567.982, "G#6": 1661.219,
|
||||||
|
"AB6": 1661.219, "A6": 1760.000, "A#6": 1864.655, "BB6": 1864.655,
|
||||||
|
"B6": 1975.533,
|
||||||
|
|
||||||
|
"C7": 2093.005, "C#7": 2217.461, "DB7": 2217.461, "D7": 2349.318,
|
||||||
|
"D#7": 2489.016, "EB7": 2489.016, "E7": 2637.020, "F7": 2793.826,
|
||||||
|
"F#7": 2959.955, "GB7": 2959.955, "G7": 3135.963, "G#7": 3322.438,
|
||||||
|
"AB7": 3322.438, "A7": 3520.000, "A#7": 3729.310, "BB7": 3729.310,
|
||||||
|
"B7": 3951.066,
|
||||||
|
|
||||||
|
"C8": 4186.009
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let note = 261.626; // default C4
|
||||||
|
let notesToPlay = [];
|
||||||
|
|
||||||
|
function flushNotes() {
|
||||||
|
if (notesToPlay.length === 0) return;
|
||||||
|
|
||||||
|
|
||||||
|
let baseVolume = 0.2;
|
||||||
|
let volume = baseVolume / Math.sqrt(notesToPlay.length);
|
||||||
|
|
||||||
|
for (let f of notesToPlay) {
|
||||||
|
playNote(f, 1, "sine", volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
notesToPlay = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.note_block = {
|
||||||
|
color: "#965500",
|
||||||
|
behavior: behaviors.WALL,
|
||||||
|
onSelect() {
|
||||||
|
promptInput(
|
||||||
|
"Select the note this note block should be",
|
||||||
|
function (choice) {
|
||||||
|
if (!choice) {
|
||||||
|
if (!note) { note = 261.626; }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let key = choice.toUpperCase();
|
||||||
|
if (key in pianoFrequencies) {
|
||||||
|
note = pianoFrequencies[key];
|
||||||
|
} else {
|
||||||
|
note = 261.626; // fallback = C4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Note prompt"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onPlace(pixel) {
|
||||||
|
pixel.note = note;
|
||||||
|
},
|
||||||
|
tick(pixel) {
|
||||||
|
if (pixel.charge) {
|
||||||
|
notesToPlay.push(Number(pixel.note));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
conduct: 1,
|
||||||
|
category: "machines"
|
||||||
|
};
|
||||||
|
|
||||||
|
runEveryTick(function () { flushNotes() });
|
||||||
|
|
||||||
|
/*
|
||||||
|
elements.uncook = {
|
||||||
|
color: ["#4dcdff", "#70ddff", "#bcddff", "#ffffff"],
|
||||||
|
category: "tools",
|
||||||
|
tool(pixel) {
|
||||||
|
if (!pixel || !pixel.element) return;
|
||||||
|
|
||||||
|
// 1) If the current element itself defines stateLow, use it (common case)
|
||||||
|
const cur = elements[pixel.element];
|
||||||
|
if (cur && cur.stateLow !== undefined) {
|
||||||
|
const low = cur.stateLow;
|
||||||
|
pixel.element = Array.isArray(low) ? low[Math.floor(Math.random() * low.length)] : low;
|
||||||
|
if (typeof pixel.temp === "number") pixel.temp = Math.max(0, pixel.temp - 1);
|
||||||
|
return; // done
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Otherwise search for an element whose stateHigh === the current element
|
||||||
|
for (const key in elements) {
|
||||||
|
const el = elements[key];
|
||||||
|
if (!el) continue;
|
||||||
|
if (el.stateHigh === pixel.element) {
|
||||||
|
// 'key' is the low-state element name
|
||||||
|
changePixel(pixel, key)
|
||||||
|
if (typeof pixel.temp === "number") pixel.temp = Math.max(0, pixel.temp - 1);
|
||||||
|
return; // done
|
||||||
|
}
|
||||||
|
// If el.stateHigh can be an array of high-state names:
|
||||||
|
if (Array.isArray(el.stateHigh) && el.stateHigh.includes(pixel.element)) {
|
||||||
|
changePixel(pixel, key)
|
||||||
|
if (typeof pixel.temp === "number") pixel.temp = Math.max(0, pixel.temp - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
elements.roman_cement = {
|
||||||
|
color: "#b8b8b8",
|
||||||
|
behavior: behaviors.LIQUID,
|
||||||
|
category: "liquids",
|
||||||
|
viscosity: 1000,
|
||||||
|
density: 1400,
|
||||||
|
state: "solid",
|
||||||
|
tempLow: -10,
|
||||||
|
stateLow: "roman_concrete",
|
||||||
|
tempHigh: 1550,
|
||||||
|
stateHigh: "magma",
|
||||||
|
tick(pixel) {
|
||||||
|
if (pixelTicks - pixel.start > 100 && Math.random() <= 0.1) {
|
||||||
|
changePixel(pixel, "roman_concrete")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.roman_concrete = {
|
||||||
|
color: "#ababab",
|
||||||
|
behavior: behaviors.SUPPORT,
|
||||||
|
tempHigh: 1500,
|
||||||
|
stateHigh: "magma",
|
||||||
|
category: "powders",
|
||||||
|
state: "solid",
|
||||||
|
density: 2400,
|
||||||
|
hardness: 0.5,
|
||||||
|
breakInto: "dust",
|
||||||
|
darkText: true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} element
|
||||||
|
* @param {object} reaction
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function doWaterReactions(element, reaction) {
|
||||||
|
if (!elements[element].reactions) {
|
||||||
|
elements[element].reactions = {}
|
||||||
|
}
|
||||||
|
elements[element].reactions.water = reaction
|
||||||
|
elements[element].reactions.salt_water = reaction
|
||||||
|
elements[element].reactions.pool_water = reaction
|
||||||
|
elements[element].reactions.sugar_water = reaction
|
||||||
|
elements[element].reactions.dirty_water = reaction
|
||||||
|
elements[element].reactions.selter = reaction
|
||||||
|
elements[element].reactions.primordial_soup = reaction
|
||||||
|
elements[element].reactions.nut_milk = reaction
|
||||||
|
}
|
||||||
|
|
||||||
|
doWaterReactions("slaked_lime", {elem1:"roman_cement", elem2: null, chance: 0.25})
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue