Sidewall belt and screen drawing, cheaper cleat checks (t42, t43)

Far sidewall drawn behind the load with cleat ribs at their physics
positions; sloped screens get a tinted mesh between rails and shake only
when loaded. Powder skips cleat checks outside chunks that have cleats,
and empty slopes let their chunks sleep. Record the screw conveyor and
stall/carry-depth decisions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 20:08:21 -04:00
co-authored by Claude Opus 5.5
parent 578b55316b
commit 3ee85429fd
14 changed files with 248 additions and 59 deletions
+17 -2
View File
@@ -3,6 +3,7 @@ const CLEAT_SPACING = 8, CLEAT_HEIGHT = 6; // spacing in face cells, height in g
const CLEAT_REACH = Math.floor(CLEAT_HEIGHT * Math.SQRT1_2);
const SCREEN_NUDGE_TICKS = 4; // one downhill contact step per four ticks (15 steps/s), plus gravity
let cleatCarrying = false;
let cleatChunks = new Uint8Array(0);
let cleatMask = new Uint8Array(0), cleatCells = [], slopePhase = new Uint8Array(0);
function cleatFoot(x, b, phase = slopePhase[b]) {
const d = blockV[b] & 1 ? 1 : -1;
@@ -16,7 +17,8 @@ function pocketDepth(x, b) {
return Math.max(0, CLEAT_REACH * 2 - distance);
}
function slopeCleatsTick(advance = true) {
for (const i of cleatCells) { cleatMask[i] = 0; wakeIdx(i); }
for (const i of cleatCells) { cleatMask[i] = 0; wakeCleatLoad(i); }
cleatChunks.fill(0);
cleatCells.length = 0;
// Front first, just like flat transport. Each foot belongs to exactly one face cell.
for (const list of [beltR, beltL]) for (const i of list) {
@@ -37,7 +39,12 @@ function slopeCleatsTick(advance = true) {
if ((x & 3) === 0 && isBelt(c) && isSlopeBelt(c) && beltFaceY(c,x>>2,y>>2,x)===y && netSat(i)>0)
slopePhase[b] = (slopePhase[b] + 1) % CLEAT_SPACING;
}
for (const i of cleatCells) { cleatMask[i] = 1; wakeIdx(i); }
for (const i of cleatCells) {
cleatMask[i] = 1; wakeCleatLoad(i);
const x = i % W, y = (i / W) | 0;
for (let cy = Math.max(0, (y - 1) >> 5); cy <= Math.min(CH - 1, (y + 1) >> 5); cy++)
for (let cx = Math.max(0, (x - 1) >> 5); cx <= Math.min(CW - 1, (x + 1) >> 5); cx++) cleatChunks[cy * CW + cx] = 1;
}
}
// A screen shakes only the grains touching its mesh, never the whole column above it.
function screenNudge(top, d, pass) {
@@ -49,3 +56,11 @@ function screenNudge(top, d, pass) {
if (i % W + d < 0 || i % W + d >= W || j >= N) return;
if (enter(m, PH_POWDER, j, d, 1)) move(i, j, i % W, (i / W) | 0, j % W, (j / W) | 0);
}
// Only loose load can react to a barrier appearing or disappearing.
function wakeCleatLoad(i) {
const x = i % W, y = (i / W) | 0;
for (let yy = Math.max(0, y - 1); yy <= Math.min(H - 1, y + 1); yy++)
for (let xx = Math.max(0, x - 1); xx <= Math.min(W - 1, x + 1); xx++)
if (PH[mat[yy * W + xx]] === PH_POWDER || occ[yy * W + xx]) wakeXY(xx, yy);
}