Water pours off ledges several times faster, raining clouds spread boiled-off water (t21)
- Liquids step up to 8 cells a tick toward a drop (fewer the thicker they are), and a top-layer grain looks 4 times as far for one, so pools empty and thin film drains. A 100-wide pool empties in about 50 s; the old code left 24-650 grains stranded on wide ledges. - Only a top-layer grain stepping sideways wakes the row ahead, so settled lakes still sleep. - World generation settles at the old speed: seeds make the same worlds as before. - Cooled steam under a roof no longer stays steam for ever (its heat area slept). - Raining clouds keep drifting at half pace and rain over a band either side, so a waterfall into a hot shaft no longer rains straight back on its own lake. - New test/t_water.js; t_weather rain-location checks; t_conveyors counts steam in flight; t_molds seeds the random burning-bed check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+15
-4
@@ -21,6 +21,13 @@ function swapCells(i, j) {
|
||||
function move(i, j, x, y, nx, ny) {
|
||||
swapCells(i, j);
|
||||
wakeXY(x, y); wakeXY(nx, ny);
|
||||
if (ny === y && LFILM > 1 && PH[mat[j]] === PH_LIQUID && (y === 0 || PH[mat[i - W]] !== PH_LIQUID)) {
|
||||
// a top-layer grain stepping sideways may clear the path to a drop for surface grains far
|
||||
// along the row, so wake them; moves inside a body of water do not (settled lakes must sleep)
|
||||
const reach = SPREAD[mat[j]] * LFILM, row = (y >> 5) * CW;
|
||||
const first = Math.max(0, x - reach) >> 5, last = Math.min(W - 1, x + reach) >> 5;
|
||||
for (let cx = first; cx <= last; cx++) awake[row + cx] = 3;
|
||||
}
|
||||
if (part[j] === P_WHEEL) { const mm = machines[mach[j]]; if (mm) mm.flow += PH[mat[j]] === PH_LIQUID ? 1 : 0.5; }
|
||||
const d = temp[j] - AMB[ny];
|
||||
if (d > 25 || d < -25) wakeHeatXY(nx, ny);
|
||||
@@ -55,6 +62,10 @@ function enter(m, ph, j, dx, dy) {
|
||||
// Heavy grains settle through a loose pile of much lighter ones, slowly. A sorting
|
||||
// step keeps its area awake for a while so a pile finishes sorting even at rest.
|
||||
let SORTP = 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.
|
||||
let LSTEP = 8, LFILM = 4;
|
||||
function powder(i, x, y, m) {
|
||||
if (y >= H - 1) return;
|
||||
const b = i + W;
|
||||
@@ -97,7 +108,7 @@ function liquid(i, x, y, m) {
|
||||
if (nx >= 0 && nx < W && enter(m, PH_LIQUID, b - d, -d, 1)) { move(i, b - d, x, y, nx, y + 1); return; }
|
||||
}
|
||||
if (rnd() > FLUID[m]) return;
|
||||
const sp = SPREAD[m];
|
||||
const sp = SPREAD[m] * (y === 0 || PH[mat[i - W]] !== PH_LIQUID ? LFILM : 1);
|
||||
const d0 = (RS & 4) ? 1 : -1;
|
||||
for (let pass = 0; pass < 2; pass++) {
|
||||
const d = pass ? -d0 : d0;
|
||||
@@ -107,8 +118,8 @@ function liquid(i, x, y, m) {
|
||||
const j = i + d * s;
|
||||
if (!passable(m, PH_LIQUID, j, d, 0)) break;
|
||||
if (y < H - 1 && passable(m, PH_LIQUID, j + W, 0, 1)) {
|
||||
// step one cell toward the drop (keeps flow continuous and local)
|
||||
move(i, i + d, x, y, x + d, y);
|
||||
const k = Math.min(s, Math.max(1, (LSTEP * FLUID[m]) | 0)); // thick liquids take shorter steps
|
||||
move(i, i + d * k, x, y, x + d * k, y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -127,7 +138,7 @@ function gas(i, x, y, m) {
|
||||
if (l <= 1) { mat[i] = EMPTY; life[i] = 0; wakeXY(x, y); return; }
|
||||
life[i] = l - 1;
|
||||
}
|
||||
}
|
||||
} else if (m === STEAM && temp[i] < CONDT[STEAM]) wakeHeatXY(x, y); // cooled steam drifting under a roof needs the heat pass to condense it
|
||||
if (y === 0 || (m === STEAM && y <= weather.skyY + 4 && y < roofY[x])) {
|
||||
// steam that has risen to cloud height in the open sky joins the clouds
|
||||
if (m === STEAM) absorbSteam(x);
|
||||
|
||||
+6
-4
@@ -71,15 +71,17 @@ function weatherTick() {
|
||||
if (sh.left !== undefined) { sh.left -= made; if (sh.left <= 0 && sh.until > tick) sh.until = tick; } // made up the shortfall: it passes
|
||||
}
|
||||
}
|
||||
// clouds made of your steam build up, then rain it back out where they hang
|
||||
// clouds made of your steam build up, then rain it back out over where they hang and a band
|
||||
// either side, so water boiled off one spot does not all fall back on it
|
||||
for (let b = 0; b < n; b++) {
|
||||
if (!w.raining[b] && w.moist[b] > 150) w.raining[b] = 1;
|
||||
if (w.raining[b]) { w.moist[b] -= spawnRain(b * WBAND, (b + 1) * WBAND, Math.min(3, 0.5 + w.moist[b] / 100)); if (w.moist[b] < 12) w.raining[b] = 0; }
|
||||
if (w.raining[b]) { w.moist[b] -= spawnRain(Math.max(0, (b - 1) * WBAND), Math.min(W, (b + 2) * WBAND), Math.min(3, 0.5 + w.moist[b] / 100)); if (w.moist[b] < 12) w.raining[b] = 0; }
|
||||
}
|
||||
// and drift a little downwind every second; at the edge of the world they pile up instead
|
||||
// and drift a little downwind every second, raining ones at half the pace; at the edge of the
|
||||
// world they pile up instead
|
||||
if (tick % 60 === 0) {
|
||||
const out = new Float32Array(n), d = w.wind > 0 ? 1 : -1, f = Math.min(0.12, Math.abs(w.wind) * 0.1);
|
||||
for (let b = 0; b < n; b++) { const mv = w.raining[b] ? 0 : w.moist[b] * f; out[b] += w.moist[b] - mv; if (b + d >= 0 && b + d < n) out[b + d] += mv; else out[b] += mv; }
|
||||
for (let b = 0; b < n; b++) { const mv = w.moist[b] * f * (w.raining[b] ? 0.5 : 1); out[b] += w.moist[b] - mv; if (b + d >= 0 && b + d < n) out[b + d] += mv; else out[b] += mv; }
|
||||
w.moist = out;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -303,8 +303,9 @@ function* worldSteps(seedIn, w, h) {
|
||||
}
|
||||
fillNoise();
|
||||
yield [0.75, 'Settling loose ground'];
|
||||
// settle loose material
|
||||
// settle loose material, with water at the speed it had when the seeds were made
|
||||
awake.fill(3);
|
||||
const lstep = LSTEP, lfilm = LFILM; LSTEP = LFILM = 1;
|
||||
for (let k = 0; k < 260; k++) {
|
||||
tick++; tickStamp = (tickStamp % 255) + 1;
|
||||
simMove();
|
||||
@@ -312,6 +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;
|
||||
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