Piles near the bot sort, and 20 times faster; burning fuel keeps the slow pace (t21)
- SORTP 0.003 -> 0.06: ore sinks through 8 rows of ash in about 7 s near the bot. - wakeBotPowder(): every 8 ticks, areas with loose grains within 100 grains of the bot get a sorting chance; far away, resting piles still sleep. - Sinking through burning fuel stays at 0.003, so buried burning piles still char and furnace beds behave as tuned. World generation settles at the old rate: seeds are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+22
-5
@@ -59,9 +59,12 @@ function enter(m, ph, j, dx, dy) {
|
||||
}
|
||||
|
||||
// ---------- Movement ----------
|
||||
// Heavy grains settle through a loose pile of much lighter ones, slowly. A sorting
|
||||
// Heavy grains settle through a loose pile of much lighter ones. A sorting
|
||||
// step keeps its area awake for a while so a pile finishes sorting even at rest.
|
||||
let SORTP = 0.003;
|
||||
// Through burning fuel it stays slow: a furnace bed is tuned to it, and dirt heaped on a burning
|
||||
// pile has to smother it into charcoal, not sink through.
|
||||
let SORTP = 0.06;
|
||||
const SORTP_FUEL = 0.003;
|
||||
// Liquids step up to LSTEP cells toward a drop in one tick (fewer the thicker they are), and a top-layer grain looks LFILM
|
||||
// times as far for one (a two-times range strands the far end of a 200-grain-wide ledge).
|
||||
// World generation settles with both at 1, so every seed keeps making the same world.
|
||||
@@ -73,7 +76,7 @@ function powder(i, x, y, m) {
|
||||
// a grain at least twice as dense works its way down through a loose pile. Unlit fuel
|
||||
// packs too tight for that, so a mixed furnace charge stays mixed until the fire gets in.
|
||||
const t = mat[b];
|
||||
if (PH[t] === PH_POWDER && DENS[m] >= DENS[t] * 2 && (!FUEL[t] || (flags[b] & F_BURN)) && stamp[b] !== tickStamp && !occ[b] && part[b] !== P_GRATE && part[b] !== P_FILTER && rnd() < SORTP) { move(i, b, x, y, x, y + 1); awake[(y >> 5) * CW + (x >> 5)] = 40; return; }
|
||||
if (PH[t] === PH_POWDER && DENS[m] >= DENS[t] * 2 && (!FUEL[t] || (flags[b] & F_BURN)) && stamp[b] !== tickStamp && !occ[b] && part[b] !== P_GRATE && part[b] !== P_FILTER && rnd() < (FUEL[t] ? SORTP_FUEL : SORTP)) { move(i, b, x, y, x, y + 1); awake[(y >> 5) * CW + (x >> 5)] = 40; return; }
|
||||
// a grain lying right on a belt or filter is held by it: the surface carries it, it does not slide off the edge
|
||||
if (t === BELTL || t === BELTR || part[b] === P_FILTER) return;
|
||||
if (rnd() < STICK[m]) {
|
||||
@@ -158,11 +161,23 @@ function gas(i, x, y, m) {
|
||||
if (nx >= 0 && nx < W && mat[i + d] === EMPTY && passable(m, PH_GAS, i + d, d, 0)) { move(i, i + d, x, y, nx, y); }
|
||||
}
|
||||
}
|
||||
function wakeBotPowder() {
|
||||
const x = bot.x + bot.w / 2, y = bot.y + bot.h / 2;
|
||||
const x0 = Math.max(0, Math.floor((x - 100) / 32)), x1 = Math.min(CW - 1, Math.floor((x + 100) / 32));
|
||||
const y0 = Math.max(0, Math.floor((y - 100) / 32)), y1 = Math.min(CH - 1, Math.floor((y + 100) / 32));
|
||||
for (let cy = y0; cy <= y1; cy++) for (let cx = x0; cx <= x1; cx++) {
|
||||
const c = cy * CW + cx;
|
||||
if (!powderArea[c] || awake[c]) continue;
|
||||
const dx = Math.max(cx * 32 - x, 0, x - (cx * 32 + 31));
|
||||
const dy = Math.max(cy * 32 - y, 0, y - (cy * 32 + 31));
|
||||
if (dx * dx + dy * dy <= 10000) awake[c] = 1;
|
||||
}
|
||||
}
|
||||
function simMove() {
|
||||
for (let cy = CH - 1; cy >= 0; cy--) {
|
||||
const rowBase = cy * CW;
|
||||
let any = false;
|
||||
for (let cx = 0; cx < CW; cx++) if (awake[rowBase + cx]) { any = true; break; }
|
||||
for (let cx = 0; cx < CW; cx++) if (awake[rowBase + cx]) { any = true; powderArea[rowBase + cx] = 0; }
|
||||
if (!any) continue;
|
||||
const y0 = cy << 5, y1 = Math.min(H, y0 + 32);
|
||||
for (let y = y1 - 1; y >= y0; y--) {
|
||||
@@ -176,8 +191,10 @@ function simMove() {
|
||||
const dx = ltr ? 1 : -1, xEnd = ltr ? x1 : x0 - 1;
|
||||
for (let x = ltr ? x0 : x1 - 1; x !== xEnd; x += dx) {
|
||||
const i = yw + x, m = mat[i];
|
||||
if (m === EMPTY || stamp[i] === tickStamp) continue;
|
||||
if (m === EMPTY) continue;
|
||||
const ph = PH[m];
|
||||
if (ph === PH_POWDER) powderArea[rowBase + cx] = 1;
|
||||
if (stamp[i] === tickStamp) continue;
|
||||
if (ph === PH_SOLID) continue;
|
||||
const p = part[i];
|
||||
if (p >= P_TU && p <= P_TR && ph === PH_POWDER) continue; // a screw tube moves its own grains
|
||||
|
||||
@@ -10,6 +10,7 @@ function simTick() {
|
||||
pulseTick();
|
||||
entTick();
|
||||
if (flyers.length) flyTick();
|
||||
if (tick % 8 === 0) wakeBotPowder();
|
||||
simMove();
|
||||
heatPass();
|
||||
for (let c = 0; c < NCH; c++) if (awake[c]) awake[c]--;
|
||||
|
||||
+2
-1
@@ -13,7 +13,7 @@ let ents = []; // loose objects (bars)
|
||||
let bgm; // background layer: trees. Liquids, powders and gases pass in front of it.
|
||||
let flyers = []; // grains in flight, blown out of the bot
|
||||
let ghostBlocks = new Map(), ghostMolds = [];
|
||||
let awake, hot, hotLvl;
|
||||
let awake, hot, hotLvl, powderArea;
|
||||
let tick = 0, tickStamp = 1;
|
||||
let machines = [null], molds = [], nets = [null], pcells = new Set(), powerDirty = true;
|
||||
let beltL = [], beltR = [], tubeLists = [[], [], [], [], []];
|
||||
@@ -50,6 +50,7 @@ function alloc(w, h) {
|
||||
surfY = new Int16Array(w); roofY = new Int16Array(w); dirtY = new Int16Array(w); graniteY = new Int16Array(w); basaltY = new Int16Array(w); magmaY = new Int16Array(w);
|
||||
AMB = new Float32Array(h);
|
||||
awake = new Uint8Array(NCH); hot = new Uint8Array(NCH); hotLvl = new Uint8Array(NCH);
|
||||
powderArea = new Uint8Array(NCH).fill(1); // unknown areas get one visit before being ruled out
|
||||
machines = [null]; molds = []; nets = [null]; pcells = new Set(); powerDirty = true;
|
||||
beltL = []; beltR = []; tubeLists = [[], [], [], [], []]; brokenMachines = [];
|
||||
ghostMachines = []; ghostBlocked = new Set();
|
||||
|
||||
+3
-3
@@ -303,9 +303,9 @@ function* worldSteps(seedIn, w, h) {
|
||||
}
|
||||
fillNoise();
|
||||
yield [0.75, 'Settling loose ground'];
|
||||
// settle loose material, with water at the speed it had when the seeds were made
|
||||
// settle loose material at the water and sorting speeds the seeds were made with
|
||||
awake.fill(3);
|
||||
const lstep = LSTEP, lfilm = LFILM; LSTEP = LFILM = 1;
|
||||
const lstep = LSTEP, lfilm = LFILM, sortp = SORTP; LSTEP = LFILM = 1; SORTP = 0.003;
|
||||
for (let k = 0; k < 260; k++) {
|
||||
tick++; tickStamp = (tickStamp % 255) + 1;
|
||||
simMove();
|
||||
@@ -313,7 +313,7 @@ function* worldSteps(seedIn, w, h) {
|
||||
if (!any) break;
|
||||
if ((k & 31) === 0) yield [0.75 + 0.24 * k / 260, 'Settling loose ground'];
|
||||
}
|
||||
LSTEP = lstep; LFILM = lfilm;
|
||||
LSTEP = lstep; LFILM = lfilm; SORTP = sortp;
|
||||
yield [0.99, 'Finishing'];
|
||||
// re-ambient after settling, then start clean
|
||||
for (let i = 0; i < N; i++) { const m = mat[i]; if (m !== MAGMA) temp[i] = AMB[(i / w) | 0]; life[i] = PH[m] === PH_LIQUID && FRZ[m] ? 255 : 0; }
|
||||
|
||||
Reference in New Issue
Block a user