diff --git a/mods/cubesstuff.js b/mods/cubesstuff.js new file mode 100644 index 00000000..0421591c --- /dev/null +++ b/mods/cubesstuff.js @@ -0,0 +1,161 @@ +//broken rn dont know how to fix it yet +/* +elements.button = { + color: "#970000", + conduct: 1, + charge: 0, + category: "machines", + onSelect: function () { + logMessage("Click the button with no elements equipped to charge the button.") + }, + properties: { + clicked: false, + clickTime: 1, + }, + onClicked: function (pixel) { + pixel.clicked = true + pixel.clickTime = 1 + }, + tick: function (pixel) { + if (pixel.clicked == true && pixel.clickTime > 0) { + pixel.charge = 1 + pixel.clickTime-- + } + else if (pixel.clicked == true && pixel.clickTime <= 0) { + pixel.clicked = false + pixel.charge = 0 + } + } +} +*/ +elements.aerogel = { + color: "#79ffff", + category: "solids", + behavior: behaviors.WALL, + state: "solid", + tempHigh: 1200, + stateHigh: "ash", + insulate: true, + density: 0.2, + hardness: 0.1, + breakInto: "dust", + onPlace: function (pixel) { + if (pixel.alpha === undefined) { pixel.alpha = Math.random() * (0.5 - 0.4) + 0.4 } + } +} + +let oldCopperReactions = elements.copper.reactions +elements.molten_copper.reactions.molten_aluminum = { elem1: "molten_nordic_gold", elem2: null, chance: 0.5 } +elements.acid.ignore.push("nordic_gold") +elements.acid.ignore.push("nordic_gold_coin") + +elements.nordic_gold = { + color: ["#f1db7c", "#e5c34b", "#d2a742", "#b98c31", "#a47320"], + tempHigh: 1060, + behavior: behaviors.WALL, + category: "solids", + state: "solid", + density: 8800, + conduct: 0.90, + breakInto: "nordic_gold_coin" +} + +elements.nordic_gold_coin = { + color: ["#f1db7c", "#e5c34b", "#d2a742", "#b98c31", "#a47320"], + tempHigh: 1060, + stateHigh: "molten_nordic_gold", + behavior: behaviors.POWDER, + category: "powders", + state: "solid", + density: 8800, + conduct: 0.90, + alias: "euro_coin", + reactions: { + "glue": { elem1: "nordic_gold", elem2: null } + } +} + +function randomColor() { + const letters = "0123456789ABCDEF"; + let color = "#"; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; +} + +elements.disco_ball = { + color: "#ebebc3", + buttonColor: ["#ff0000", "#ff8800", "#ffff00", "#00ff00", "#00ffff", "#0000ff", "#ff00ff"], + renderer: renderPresets.LED, + behavior: behaviors.WALL, + category: "machines", + tempHigh: 1500, + stateHigh: ["molten_glass", "molten_glass", "molten_copper"], + conduct: 1, + breakInto: "glass_shard", + forceSaveColor: true, + tick: function (pixel) { + for (var i = 0; i < squareCoords.length; i++) { + var coord = squareCoords[i]; + var x = pixel.x + coord[0]; + var y = pixel.y + coord[1]; + if (pixel.charge > 0) { + pixel.color = randomColor() + if (isEmpty(x, y)) { + createPixel("light", x, y) + let p = getPixel(x, y) + if (p !== null && p.element == "light") { + p.color = pixel.color + } + } + } + else { pixel.color = "#ebebc3" } + } + } +} + +elements.molten_iron.reactions.sulfur = { elem1: "pyrite", elem2: null, chance: 0.25 } +elements.molten_iron.reactions.molten_sulfur = { elem1: "pyrite", elem2: null, chance: 0.25 } +elements.molten_iron.reactions.sulfur_gas = { elem1: "pyrite", elem2: null, chance: 0.25 } + +elements.pyrite = { + color: ["#d8c25e", "#bbaa49", "#998f3e"], + alias: ["fools_gold", "Iron Disulfide"], + density: 5000, + tempHigh: 1177, + stateHigh: ["iron", "molten_sulfur"], + grain: 0.4, + state: "solid", + behavior: behaviors.WALL, + category: "solids" +} + +elements.fire_extinguisher_powder = { + color: "#ececec", + behavior: [ + "XX|XX|XX", + "XX|DL%1|XX", + "M2%30|M1%30|M2%30" + ], + extinguish: true, + tick: function (pixel) { + 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 (getPixel(x, y)?.burning === true) { + let elem = getPixel(x, y) + elem.burning = false + } + } + }, + tool: function(pixel) { + if(pixel.burning === true){ + delete pixel.burning; + delete pixel.burnStart; + } + }, + canPlace: true, + category: "powders" +} \ No newline at end of file diff --git a/mods/fans.js b/mods/fans.js new file mode 100644 index 00000000..a3bf07ad --- /dev/null +++ b/mods/fans.js @@ -0,0 +1,211 @@ +function getSelfMovingBehaviorFunctionNames() { + return Object.entries(behaviors) + .filter(([name, func]) => { + if (typeof func !== "function") return false; + if (["SEEDRISE"].includes(name)) return false; + + const code = func.toString(); + + // Only allow if it's moving its own pixel + const selfMove = /movePixel\s*\(\s*pixel\s*,/.test(code) || /tryMove\s*\(\s*pixel\s*,/.test(code) + || /pixel\.(x|y)\s*[\+\-]=/.test(code); + + return selfMove; + }) + .map(([name]) => name); +} + +const builtInMovementBehaviors = [ + "M1", "M2","BO", "SP", "XX|M1", "M1|M2", "M1%", "M2%", "M1%|M2", + "M1|M2%", "M1%|M2%", 'XX|M1%', 'M1%|XX', 'XX|M2%', 'M2%|XX' +]; + +function behaviorIncludesMovement(behaviorMatrix, movementFunctionNames) { + if (!Array.isArray(behaviorMatrix)) return false; + + for (const row of behaviorMatrix) { + if (!Array.isArray(row)) continue; + + for (const cell of row) { + if (typeof cell !== "string") continue; + + // Handle "AND" logic: multiple behaviors in one cell + const andParts = cell.split("AND"); + + for (const andPart of andParts) { + const parts = andPart.trim().split("|").map(p => p.trim()); + if (parts.some(p => builtInMovementBehaviors.includes(p) || movementFunctionNames.includes(p))) { + return true; + } + } + } + } + + return false; +} + + +runAfterAutogen(function () { + const movementFunctionNames = getSelfMovingBehaviorFunctionNames(); + + const movableElements = Object.entries(elements).filter(([name, elem]) => { + const behavior = elem.behavior; + const tick = elem.tick || elem.tickFunc; + + let movesSelf = false; + + // Check behavior matrix + if (Array.isArray(behavior)) { + movesSelf = behaviorIncludesMovement(behavior, movementFunctionNames); + } + + // Check single string + else if (typeof behavior === "string") { + const parts = behavior.split("|").map(p => p.trim()); + movesSelf = parts.some(p => builtInMovementBehaviors.includes(p) || movementFunctionNames.includes(p)); + } + + // Check function-type behavior + else if (typeof behavior === "function") { + movesSelf = movementFunctionNames.includes(behavior.name); + } + + // Check tick function + if (!movesSelf && typeof tick === "function") { + const code = tick.toString(); + if (/movePixel\s*\(\s*pixel\s*,/.test(code) || /tryMove\s*\(\s*pixel\s*,/.test(code) || /pixel\.(x|y)\s*[\+\-]=/.test(code)) { + movesSelf = true; + } + } + + return movesSelf; + }).map(([name]) => name); + + console.log("🚶 Self-Moving Elements:", movableElements); + window.movableElementsByBehavior = movableElements; +}); + + + + + + +runAfterAutogen(function () { + console.log(behaviors) +}) + +// Create a global map to track delay for each position +if (!window.fanPushDelays) { + window.fanPushDelays = new Map(); +} + +elements.fan_right = { + behavior: behaviors.WALL, + color: "#c5c5c5", + tick: function (pixel) { + const fan_strength = 10; + const delay_ticks = 2; + + for (let i = 1; i <= fan_strength; i++) { + const x = pixel.x + i; + const y = pixel.y; + + // SKIP if position is empty + if (isEmpty(x, y)) continue; + + const delem = pixelMap[x]?.[y]; + if (!delem) continue; + + // Skip non-movable elements + if (!window.movableElementsByBehavior.includes(delem.element)) continue; + + // Use position key for delay tracking + const key = `${x},${y}`; + const currentDelay = window.fanPushDelays.get(key) || 0; + + if (currentDelay >= delay_ticks) { + window.fanPushDelays.set(key, 0); + + const newX = x + 1; + if (isEmpty(newX, y)) { + movePixel(delem, newX, y); + } + } else { + window.fanPushDelays.set(key, currentDelay + 1); + } + } + }, + category: "machines" +}; + +elements.fan_left = { + behavior: behaviors.WALL, + color: "#c5c5c5", + tick: function (pixel) { + const fan_strength = 10; + const delay_ticks = 2; + + for (let i = 0; i >= -fan_strength; i--) { + const x = pixel.x + i; + const y = pixel.y; + + // SKIP if position is empty + if (isEmpty(x, y)) continue; + + const delem = pixelMap[x]?.[y]; + if (!delem) continue; + + // Skip non-movable elements + if (!window.movableElementsByBehavior.includes(delem.element)) continue; + + // Use position key for delay tracking + const key = `${x},${y}`; + const currentDelay = window.fanPushDelays.get(key) || 0; + + if (currentDelay >= delay_ticks) { + window.fanPushDelays.set(key, 0); + + const newX = x - 1; + if (isEmpty(newX, y)) { + movePixel(delem, newX, y); + } + } else { + window.fanPushDelays.set(key, currentDelay + 1); + } + } + }, + category: "machines" +}; +/* +elements.fan_up = { + behavior: behaviors.WALL, + tick: function (pixel) { + let fan_strength = 10; + let delay_ticks = 0; // delay between pushes per pixel row + if (!pixel._fan_delay) pixel._fan_delay = 0; + + if (pixel._fan_delay > 0) { + pixel._fan_delay--; + return; + } + + for (let i = 1; i <= fan_strength; i++) { + const tx = pixel.x; + const ty = pixel.y - i; + + if (!isEmpty(tx, ty)) { + const delem = pixelMap[tx]?.[ty]; + + if (!delem || !window.movableElementsByBehavior.includes(delem.element)) break; + + const above = ty - 1; + if (isEmpty(tx, above)) { + movePixel(delem, tx, above); + pixel._fan_delay = delay_ticks; + break; // only move one per tick + } + } + } + } +}; +*/