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
|
||||
// Starts at version 3
|
||||
|
||||
|
|
@ -21,8 +25,15 @@ Machines: Robot, Adjustable heater/cooler
|
|||
|
||||
Bug Fixes
|
||||
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 = {
|
||||
|
|
@ -1545,6 +1556,7 @@ function tryJump(headPixel) {
|
|||
elements.robot_head = {
|
||||
color: "#d9d9d9",
|
||||
category: "machines",
|
||||
state: "solid",
|
||||
tick(pixel) {
|
||||
const body = getPixel(pixel.x, pixel.y + 1);
|
||||
|
||||
|
|
@ -1583,6 +1595,7 @@ elements.robot_head = {
|
|||
elements.robot_body = {
|
||||
color: "#b1b1b1",
|
||||
category: "machines",
|
||||
state: "solid",
|
||||
tick(pixel) {
|
||||
const head = getPixel(pixel.x, pixel.y - 1);
|
||||
|
||||
|
|
@ -1608,6 +1621,7 @@ elements.robot_body = {
|
|||
elements.robot = {
|
||||
color: "#b1b1b1",
|
||||
category: "machines",
|
||||
state: "solid",
|
||||
onSelect() {
|
||||
promptChoose(
|
||||
"Choose robot mode",
|
||||
|
|
@ -1663,6 +1677,7 @@ elements.broken_adjustable_heater = {
|
|||
category: "extras",
|
||||
insulate: true,
|
||||
behavior: behaviors.WALL,
|
||||
|
||||
onSelect() {
|
||||
promptInput(
|
||||
"Select the temperature you want to adjust to",
|
||||
|
|
@ -1730,24 +1745,7 @@ elements.adjustable_heater = {
|
|||
} else if (current_pixel.temp > adjusted_temp) {
|
||||
current_pixel.temp = Math.max(current_pixel.temp - heatAmount, adjusted_temp);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
pixelTempCheck(current_pixel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1831,27 +1829,633 @@ elements.adjustable_cooler = {
|
|||
current_pixel.temp = Math.min(current_pixel.temp + coolAmount, adjusted_cool_temp);
|
||||
}
|
||||
|
||||
// Phase change check (forces melting/freezing/etc.)
|
||||
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);
|
||||
}
|
||||
}
|
||||
pixelTempCheck(current_pixel)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
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