Level lakes at the end of world generation, keeping their water (t96)
Volume-preserving levelling pass for water bodies of 50+ cells; the dock foundation is placed first so it cannot erase levelled water. Seed hashes re-baselined (water and air only). Started by Codex, finished and reviewed by Claude after Codex hit its usage limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// World generation helpers: noise and removal of tiny hard rock specks.
|
||||
// World generation helpers: noise, hard rock specks and lake levelling.
|
||||
// ---------- Perlin noise ----------
|
||||
function makeNoise(rng) {
|
||||
const perm = new Uint8Array(512), gx = new Float32Array(256), gy = new Float32Array(256);
|
||||
@@ -59,3 +59,73 @@ function clearHardSpecks(live) {
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// Grow each basin upward from its bottom: dry walls/rims are crossed only if filled to them.
|
||||
function levelWorldWater() {
|
||||
const seen = new Uint8Array(N), region = new Uint32Array(N), cells = new Int32Array(N), stack = new Int32Array(N);
|
||||
let tag = 0;
|
||||
for (let start = 0; start < N; start++) {
|
||||
if (mat[start] !== WATER || seen[start]) continue;
|
||||
let size = 0, sp = 1, bottom = start;
|
||||
stack[0] = start; seen[start] = 1;
|
||||
// Measure the original four-connected body before moving any of its water.
|
||||
while (sp) {
|
||||
const i = stack[--sp], x = i % W, y = (i / W) | 0;
|
||||
cells[size++] = i;
|
||||
if (i > bottom) bottom = i;
|
||||
for (let d = 0; d < 4; d++) {
|
||||
if ((d === 0 && !x) || (d === 1 && x === W - 1) || (d === 2 && !y) || (d === 3 && y === H - 1)) continue;
|
||||
const j = i + (d === 0 ? -1 : d === 1 ? 1 : d === 2 ? -W : W);
|
||||
if (mat[j] === WATER && !seen[j]) { seen[j] = 1; stack[sp++] = j; }
|
||||
}
|
||||
}
|
||||
if (size < 50) continue;
|
||||
let volume = size;
|
||||
for (let k = 0; k < size; k++) { const i = cells[k]; mat[i] = EMPTY; flags[i] = 0; }
|
||||
tag++; size = sp = 1; cells[0] = stack[0] = bottom; region[bottom] = tag;
|
||||
for (let level = (bottom / W) | 0; level >= 0; level--) {
|
||||
if (!sp && level < H - 1) {
|
||||
for (let x = 0; x < W; x++) {
|
||||
const i = level * W + x;
|
||||
if (region[i + W] === tag && (mat[i] === EMPTY || mat[i] === WATER)) {
|
||||
region[i] = tag; cells[size++] = i; stack[sp++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// At this height, fill every connected low space before rising another row.
|
||||
while (sp) {
|
||||
const i = stack[--sp], x = i % W, y = (i / W) | 0;
|
||||
if (mat[i] === WATER) { volume++; seen[i] = 1; }
|
||||
for (let d = 0; d < 4; d++) {
|
||||
if ((d === 0 && !x) || (d === 1 && x === W - 1) || (d === 2 && y <= level) || (d === 3 && y === H - 1)) continue;
|
||||
const j = i + (d === 0 ? -1 : d === 1 ? 1 : d === 2 ? -W : W);
|
||||
if (region[j] === tag || (mat[j] !== EMPTY && mat[j] !== WATER)) continue;
|
||||
region[j] = tag; cells[size++] = j; stack[sp++] = j;
|
||||
}
|
||||
}
|
||||
if (size >= volume) break;
|
||||
}
|
||||
const body = cells.subarray(0, size);
|
||||
body.sort(); // row order, with no objects allocated per grain
|
||||
for (let k = 0; k < size; k++) { const i = cells[k]; mat[i] = EMPTY; flags[i] = 0; seen[i] = 1; }
|
||||
for (let end = size; end > 0 && volume > 0;) {
|
||||
const y = (cells[end - 1] / W) | 0;
|
||||
let begin = end - 1;
|
||||
while (begin > 0 && ((cells[begin - 1] / W) | 0) === y) begin--;
|
||||
const width = end - begin;
|
||||
if (volume >= width) {
|
||||
for (let k = begin; k < end; k++) { mat[cells[k]] = WATER; flags[cells[k]] = F_NAT; }
|
||||
volume -= width;
|
||||
} else {
|
||||
const left = cells[begin] % W, right = cells[end - 1] % W, mid = (left + right) >> 1;
|
||||
for (let d = 0; volume > 0; d++) {
|
||||
const x = mid + (d & 1 ? (d + 1) >> 1 : -(d >> 1));
|
||||
if (x < left || x > right) continue;
|
||||
const i = y * W + x;
|
||||
if (region[i] === tag) { mat[i] = WATER; flags[i] = F_NAT; volume--; }
|
||||
}
|
||||
}
|
||||
end = begin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user