Screw conveyors join by the shared rule: low ends and verticals join in the corner block (t67 phase 2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,26 +5,30 @@ for (let p = P_SCREW_UR; p <= P_SCREW_UL; p++) SCREW_CLASS[p] = 19 + p - P_SCREW
|
||||
// Drawing only: the four transport lanes remain in the square block.
|
||||
let diagonalJoins = new Uint8Array(0);
|
||||
function diagonalScrewJoins(bx, by, v, planned = null) {
|
||||
// Three bits per end: 1..4 edge exits; bits 6/7 are collars.
|
||||
const dy = v === 4 || v === 6 ? -1 : 1;
|
||||
// Three bits per end: 1..4 edge exits, 5 horizontal in E, 6 vertical in E; bits 6/7 collars.
|
||||
let joins = 0;
|
||||
for (let end = 0; end < 2; end++) {
|
||||
const side = end ? 1 : -1, nx = bx + side, ny = by + side * dy;
|
||||
const nb = ny * BW + nx, next = planned && planned.get(nb);
|
||||
const nc = next ? next[0] : blockP[nb], nv = next ? next[1] : blockV[nb];
|
||||
if (nx >= 0 && ny >= 0 && nx < BW && ny < BH &&
|
||||
nc === BP_SCREW && nv >= 4 && (nv === 4 || nv === 6) === (dy < 0)) continue;
|
||||
let join = 0;
|
||||
for (const dir of [side > 0 ? 1 : 3, side * dy > 0 ? 2 : 0]) {
|
||||
const x = bx + SCREW_DIRS[dir][0], y = by + SCREW_DIRS[dir][1];
|
||||
if (x < 0 || y < 0 || x >= BW || y >= BH) continue;
|
||||
const n = y * BW + x, next = planned && planned.get(n);
|
||||
const code = next ? next[0] : blockP[n], nv = next ? next[1] : blockV[n];
|
||||
if ((code === BP_SCREW && nv < 4 && (nv & 1) === (dir & 1)) ||
|
||||
((code === BP_BELT || code === BP_FILTER) && (dir & 1))) { join = dir + 1; break; }
|
||||
}
|
||||
joins |= join << (end * 3);
|
||||
if (!join) joins |= 64 << end;
|
||||
const join = endJoin(bx, by, end, planned);
|
||||
if (join < 0) { joins |= 64 << end; continue; }
|
||||
const nb = join >> 1, next = planned && planned.get(nb);
|
||||
const code = next ? next[0] : blockP[nb], nv = next ? next[1] : blockV[nb];
|
||||
if (pieceEnds(code, nv)[join & 1].diagonal) continue;
|
||||
const horizontal = code !== BP_SCREW || (nv & 1);
|
||||
const kind = ((nb / BW) | 0) === by ? (end ? 2 : 4) : horizontal ? 5 : 6;
|
||||
joins |= kind << (end * 3);
|
||||
}
|
||||
return joins;
|
||||
}
|
||||
// Only E elbows bend a straight block: 1 rising, 2 falling, three bits per end.
|
||||
function straightScrewJoins(bx, by, v, planned = null) {
|
||||
let joins = 0;
|
||||
for (let end = 0; end < 2; end++) {
|
||||
const join = endJoin(bx, by, end, planned);
|
||||
if (join < 0) continue;
|
||||
const nb = join >> 1, next = planned && planned.get(nb);
|
||||
const code = next ? next[0] : blockP[nb], nv = next ? next[1] : blockV[nb];
|
||||
if (code === BP_SCREW && nv >= 4 && ((nb / BW) | 0) !== by && nb % BW !== bx)
|
||||
joins |= (nv === 4 || nv === 6 ? 1 : 2) << (end * 3);
|
||||
}
|
||||
return joins;
|
||||
}
|
||||
@@ -35,23 +39,28 @@ function diagonalScrewShape(x, y, b, v, joins) {
|
||||
let best = Infinity;
|
||||
for (let end = 0; end < 2; end++) {
|
||||
const join = (joins >> (end * 3)) & 7, side = end ? 1 : -1;
|
||||
const slope = v === 4 || v === 6 ? -1 : 1;
|
||||
const dx = join ? SCREW_DIRS[join - 1][0] : side * Math.SQRT1_2;
|
||||
const dy = join ? SCREW_DIRS[join - 1][1] : side * slope * Math.SQRT1_2;
|
||||
const slope = v === 4 || v === 6 ? -1 : 1, straight = v < 4, vert = straight && !(v & 1);
|
||||
const bent = straight && join;
|
||||
const diagonal = straight ? bent : !join || join >= 5;
|
||||
const grade = straight ? (join === 1 ? -1 : 1) : slope;
|
||||
const dx = diagonal ? side * (vert ? grade : 1) * Math.SQRT1_2 : straight ? (vert ? 0 : side) : SCREW_DIRS[join - 1][0];
|
||||
const dy = diagonal ? side * (vert ? 1 : grade) * Math.SQRT1_2 : straight ? (vert ? side : 0) : SCREW_DIRS[join - 1][1];
|
||||
const along = lx * dx + ly * dy, across = -lx * dy + ly * dx;
|
||||
const radius = Math.hypot(across, Math.min(0, along));
|
||||
const cap = along - (join ? 2 : 2 * Math.SQRT2);
|
||||
const sd = Math.max(radius - 2, join || (joins & (64 << end)) ? cap : -10);
|
||||
const cap = along - (diagonal ? 2 * Math.SQRT2 : 2);
|
||||
const sd = Math.max(radius - 2, !straight && (joins & (64 << end)) ? cap : -10);
|
||||
if (sd < best) {
|
||||
best = sd; diagonalAcross = side * across < 0 ? -radius : radius;
|
||||
diagonalAlong = ((b % BW) * BS + 2 + (((b / BW) | 0) * BS + 2) * (v === 4 || v === 6 ? -1 : 1)) * Math.SQRT1_2 + side * along; diagonalCap = joins & (64 << end) ? cap : -10;
|
||||
const ox = (b % BW) * BS + 2, oy = ((b / BW) | 0) * BS + 2;
|
||||
diagonalAlong = (straight ? (vert ? oy : ox) : (ox + oy * slope) * Math.SQRT1_2) + side * along;
|
||||
diagonalCap = joins & (64 << end) ? cap : -10;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
function diagonalScrewBlock(x, y, smooth) {
|
||||
const i = y * W + x, own = (y >> 2) * BW + (x >> 2);
|
||||
if (part[i] >= P_SCREW_UR && part[i] <= P_SCREW_UL) return own;
|
||||
if (IS_SCREW[part[i]] && (blockV[own] >= 4 || diagonalJoins[own])) return own;
|
||||
if (mat[i] !== EMPTY || part[i] || mach[i] || occ[i] || blockP[own]) return -1;
|
||||
let best = smooth ? 0.75 : 0, found = -1;
|
||||
for (let k = 0; k < 4; k++) {
|
||||
@@ -59,8 +68,9 @@ function diagonalScrewBlock(x, y, smooth) {
|
||||
const by = (y >> 2) + (k === 2 ? -1 : k === 3 ? 1 : 0);
|
||||
if (bx < 0 || by < 0 || bx >= BW || by >= BH) continue;
|
||||
const b = by * BW + bx, v = blockV[b];
|
||||
if (blockP[b] !== BP_SCREW || v < 4) continue;
|
||||
const joins = diagonalJoins[b] === undefined ? diagonalScrewJoins(bx, by, v) : diagonalJoins[b];
|
||||
if (blockP[b] !== BP_SCREW || (v < 4 && !diagonalJoins[b])) continue;
|
||||
const joins = diagonalJoins[b] === undefined ? (v >= 4 ? diagonalScrewJoins(bx, by, v) : straightScrewJoins(bx, by, v)) : diagonalJoins[b];
|
||||
if (v < 4 && ((v & 1) ? (x >> 2) !== bx : (y >> 2) !== by)) continue;
|
||||
const sd = diagonalScrewShape(x + 0.5, y + 0.5, b, v, joins);
|
||||
if (sd <= best) { best = sd; found = b; }
|
||||
}
|
||||
|
||||
@@ -255,29 +255,36 @@ ${SM_SLOPE_DRAW}
|
||||
float sp2 = nc == 9 ? -1.0 : nc == 10 ? 1.0 : nc == 11 ? 1.0 : -1.0;
|
||||
float a = (vert ? fract(w.x * 0.25) : fract(w.y * 0.25)) * 4.0, along = vert ? w.y : w.x;
|
||||
float screwSD = -1.0, capRing = 0.0;
|
||||
if (nc >= 19) {
|
||||
vec4 screwTag = cellAt(tTree, c);
|
||||
int screwJoins = int(screwTag.a * 255.0 + 0.5);
|
||||
// Straight bend tags use six bits; background trees use 128/255.
|
||||
bool shaped = nc >= 19 || (screwJoins > 0 && screwJoins < 64);
|
||||
if (shaped) {
|
||||
vec2 d = vec2(1.0, nc == 19 || nc == 21 ? -1.0 : 1.0);
|
||||
vec4 tag = cellAt(tTree, c);
|
||||
vec4 tag = screwTag;
|
||||
vec2 local = floor(tag.gb * 255.0 + 0.5) - 8.0 + fract(w) - 2.0;
|
||||
int joins = int(tag.a * 255.0 + 0.5);
|
||||
int joins = screwJoins;
|
||||
screwSD = 100.0;
|
||||
for (int end = 0; end < 2; end++) {
|
||||
int join = (joins >> (end * 3)) & 7;
|
||||
float side = end == 0 ? -1.0 : 1.0;
|
||||
vec2 ray = join == 0 ? vec2(side, side * (nc == 19 || nc == 21 ? -1.0 : 1.0)) * 0.70710678 :
|
||||
bool diagonal = nc >= 19 ? join == 0 || join >= 5 : join != 0;
|
||||
float grade = nc >= 19 ? d.y : join == 1 ? -1.0 : 1.0;
|
||||
vec2 ray = diagonal ? (vert ? vec2(side * grade, side) : vec2(side, side * grade)) * 0.70710678 :
|
||||
nc < 19 ? (vert ? vec2(0, side) : vec2(side, 0)) :
|
||||
join == 1 ? vec2(0, -1) : join == 2 ? vec2(1, 0) : join == 3 ? vec2(0, 1) : vec2(-1, 0);
|
||||
float t = dot(local, ray), cross2 = dot(local, vec2(-ray.y, ray.x));
|
||||
float radius = length(vec2(cross2, min(0.0, t))), cap = t - (join == 0 ? 2.82842712 : 2.0);
|
||||
float radius = length(vec2(cross2, min(0.0, t))), cap = t - (diagonal ? 2.82842712 : 2.0);
|
||||
// A connected mouth meets another opaque pipe; fading its edge leaves a seam.
|
||||
float sd = max(radius - 2.0, (joins & (64 << end)) != 0 ? cap : -10.0);
|
||||
if (sd < screwSD) {
|
||||
screwSD = sd;
|
||||
a = 2.0 + (side * cross2 < 0.0 ? -radius : radius);
|
||||
along = dot(w - local, d) * 0.70710678 + side * t;
|
||||
along = (nc >= 19 ? dot(w - local, d) * 0.70710678 : vert ? w.y - local.y : w.x - local.x) + side * t;
|
||||
capRing = (joins & (64 << end)) != 0 ? smoothstep(-0.55, -0.15, cap) : 0.0;
|
||||
}
|
||||
}
|
||||
sp2 = nc == 19 || nc == 20 ? 1.0 : -1.0;
|
||||
if (nc >= 19) sp2 = nc == 19 || nc == 20 ? 1.0 : -1.0;
|
||||
}
|
||||
float wall = 0.62;
|
||||
vec3 tc;
|
||||
@@ -298,7 +305,7 @@ ${SM_SLOPE_DRAW}
|
||||
tc = mix(tc, vec3(0.6, 0.48, 0.38), flight * (full ? 0.35 : 0.8));
|
||||
tc *= 1.0 - 0.25 * smoothstep(0.9, 1.3, abs(a - 2.0));
|
||||
}
|
||||
if (nc >= 19) {
|
||||
if (shaped) {
|
||||
bool full = own.r + own.g + own.b > 0.0;
|
||||
if (full) C = mix(C, own.rgb, 1.0 - smoothstep(0.36, 0.5, length(fract(w) - 0.5)));
|
||||
C = mix(C, tc, 1.0 - smoothstep(2.0 - px, 2.0 + px, screwSD + 2.0));
|
||||
|
||||
+5
-4
@@ -24,7 +24,7 @@ function drawWorld() {
|
||||
for (let by = Math.max(0, (vy0 >> 2) - 1); by <= Math.min(BH - 1, ((vy0 + bh) >> 2) + 1); by++) {
|
||||
for (let bx = Math.max(0, (vx0 >> 2) - 1); bx <= Math.min(BW - 1, ((vx0 + bw) >> 2) + 1); bx++) {
|
||||
const b = by * BW + bx;
|
||||
if (blockP[b] === BP_SCREW && blockV[b] >= 4) diagonalJoins[b] = diagonalScrewJoins(bx, by, blockV[b]);
|
||||
if (blockP[b] === BP_SCREW) diagonalJoins[b] = blockV[b] >= 4 ? diagonalScrewJoins(bx, by, blockV[b]) : straightScrewJoins(bx, by, blockV[b]);
|
||||
}
|
||||
}
|
||||
prepareSlopeBelts(vx0, vy0, vx0 + bw, vy0 + bh);
|
||||
@@ -179,7 +179,7 @@ function drawWorld() {
|
||||
const vert = p === P_SCREW_U || p === P_SCREW_D;
|
||||
const axis = diagonal ? Math.floor(diagonalAlong) : vert ? y : x;
|
||||
const across = diagonal ? diagonalAcross + 2 : vert ? x & 3 : y & 3;
|
||||
const dir = diagonal ? (blockV[db] >= 6 ? 1 : -1) : (p === P_SCREW_U || p === P_SCREW_L) ? 1 : -1;
|
||||
const dir = diagonal && blockV[db] >= 4 ? (blockV[db] >= 6 ? 1 : -1) : (p === P_SCREW_U || p === P_SCREW_L) ? 1 : -1;
|
||||
if (diagonal ? Math.abs(diagonalAcross) > 1.38 || diagonalCap > -0.55 : across === 0 || across === 3) { // copper casing on the two long sides; its load shows through
|
||||
if (m === EMPTY) { r = 150; g = 96; b = 64; } else { r = r * 0.72 + 44; g = g * 0.72 + 26; b = b * 0.72 + 14; }
|
||||
if (!diagonal && (axis & 3) === 0) { r -= 24; g -= 18; b -= 12; }
|
||||
@@ -339,12 +339,13 @@ function drawWorld() {
|
||||
let tr = 90, tg = 190, tb = 230;
|
||||
if (blocked) { tr = 230; tg = 70; tb = 60; }
|
||||
else if (isWall(code) && WALL_OF[v]) { const wm = WALL_OF[v]; tr = (COLR[wm] + 90) / 2; tg = (COLG[wm] + 190) / 2; tb = (COLB[wm] + 230) / 2; }
|
||||
const slope = isSlopeBelt(code), diagonal = code === BP_SCREW && v >= 4;
|
||||
const joins = slope ? slopeBeltConnections(gbx, gby, code, ghostBlocks) : diagonal ? diagonalScrewJoins(gbx, gby, v, ghostBlocks) : 0;
|
||||
const slope = isSlopeBelt(code), diagonal = code === BP_SCREW && (v >= 4 || straightScrewJoins(gbx, gby, v, ghostBlocks));
|
||||
const joins = slope ? slopeBeltConnections(gbx, gby, code, ghostBlocks) : diagonal ? (v >= 4 ? diagonalScrewJoins(gbx, gby, v, ghostBlocks) : straightScrewJoins(gbx, gby, v, ghostBlocks)) : 0;
|
||||
const caps = code === BP_BELT || code === BP_FILTER ? flatBeltCaps(b, ghostBlocks) : 3;
|
||||
for (let dy = slope ? -9 : diagonal ? -4 : 0; dy < (slope || diagonal ? 8 : BS); dy++) for (let dx = slope ? -5 : diagonal ? -4 : 0; dx < (slope ? 9 : diagonal ? 8 : BS); dx++) {
|
||||
let sd = 0;
|
||||
if (diagonal) {
|
||||
if (v < 4 && ((v & 1) ? dx < 0 || dx >= BS : dy < 0 || dy >= BS)) continue;
|
||||
const x = gbx * BS + dx, y = gby * BS + dy;
|
||||
if (x < 0 || y < 0 || x >= W || y >= H) continue;
|
||||
const i = y * W + x, n = (y >> 2) * BW + (x >> 2);
|
||||
|
||||
+2
-2
@@ -44,7 +44,7 @@ function enterFree(m, ph, j, dx, dy) {
|
||||
if (occ[j]) return 0;
|
||||
const p = part[j];
|
||||
if (p !== 0) {
|
||||
if (IS_SCREW[p]) { if (ph === PH_POWDER && SCREW_DX[p] === -dx && SCREW_DY[p] === -dy) return 0; } // liquids and gases flow through freely
|
||||
if (IS_SCREW[p]) { if (ph === PH_POWDER && !screwAccepts(p, dx, dy)) return 0; } // liquids and gases flow through freely
|
||||
else if (p === P_GRATE) { if (ph === PH_POWDER || m === MSLAG) return 0; } // thick slag does not run through a grate
|
||||
else if (p === P_INTAKE) { if (ph !== PH_GAS) return 0; }
|
||||
else if (p === P_FILTER) { if (ph === PH_POWDER && !filterPassAt(m, j)) return 0; }
|
||||
@@ -110,7 +110,7 @@ function passable(m, ph, j, dx, dy) {
|
||||
if (occ[j]) return false;
|
||||
const p = part[j];
|
||||
if (p !== 0) {
|
||||
if (IS_SCREW[p]) { if (ph === PH_POWDER && SCREW_DX[p] === -dx && SCREW_DY[p] === -dy) return false; }
|
||||
if (IS_SCREW[p]) { if (ph === PH_POWDER && !screwAccepts(p, dx, dy)) return false; }
|
||||
else if (p === P_GRATE) { if (ph === PH_POWDER || m === MSLAG) return false; }
|
||||
else if (p === P_INTAKE) { if (ph !== PH_GAS) return false; }
|
||||
else if (p === P_FILTER) { if (ph === PH_POWDER && !filterPassAt(m, j)) return false; }
|
||||
|
||||
+38
-13
@@ -176,23 +176,48 @@ function screwIntake(i, p, dx, dy) {
|
||||
}
|
||||
}
|
||||
|
||||
// Four lanes cross a block in four beats; the casing carries every lane across the corner.
|
||||
// Prefer the next diagonal block, then either straight join, then the open head.
|
||||
// Powder may enter any screw except one pushing exactly against it.
|
||||
function screwAccepts(p, dx, dy) {
|
||||
return SCREW_DX[p] !== -dx || SCREW_DY[p] !== -dy;
|
||||
}
|
||||
// Straight mouths retain side-feeding into lifts; only diagonal transfers need a join.
|
||||
function straightScrewNext(i, p) {
|
||||
const dx = SCREW_DX[p], dy = SCREW_DY[p], x = i % W, y = (i / W) | 0;
|
||||
const xx = x + dx, yy = y + dy, next = yy * W + xx;
|
||||
if ((xx >> 2) === (x >> 2) && (yy >> 2) === (y >> 2)) return next;
|
||||
const end = dx + dy > 0 ? 1 : 0;
|
||||
const q = part[next], nb = (yy >> 2) * BW + (xx >> 2);
|
||||
if (blockP[nb] && !(SCREW_DX[q] && SCREW_DY[q])) return next;
|
||||
const join = endJoin(x >> 2, y >> 2, end);
|
||||
if (join >= 0) {
|
||||
const target = join >> 1, v = blockV[target];
|
||||
if (blockP[target] === BP_SCREW && v >= 4) {
|
||||
if (target === nb) return next;
|
||||
if (!blockP[nb]) {
|
||||
const lane = dx ? y & 3 : x & 3;
|
||||
const tx = target % BW * BS + (join & 1 ? BS - 1 : 0);
|
||||
return (((target / BW) | 0) * BS + lane) * W + tx;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SCREW_DX[q] && SCREW_DY[q] ? -1 : next;
|
||||
}
|
||||
// Four lanes cross a block in four beats; only a mutual geometric join can receive them.
|
||||
function diagonalScrewNext(i, p) {
|
||||
const x = i % W, y = (i / W) | 0, dx = SCREW_DX[p], dy = SCREW_DY[p];
|
||||
const xx = x + dx, bx = x & ~3, by = y & ~3;
|
||||
const xx = x + dx;
|
||||
if (xx < 0 || xx >= W) return -1;
|
||||
if ((xx >> 2) === (x >> 2)) return i + dx;
|
||||
const yy = y + dy * BS;
|
||||
if (yy >= 0 && yy < H) {
|
||||
const q = part[yy * W + xx];
|
||||
if (q >= P_SCREW_UR && q <= P_SCREW_UL && SCREW_DX[q] === dx && SCREW_DY[q] === dy) return yy * W + xx;
|
||||
const yy = y + dy * BS, join = endJoin(x >> 2, y >> 2, dx > 0 ? 1 : 0);
|
||||
if (join >= 0) {
|
||||
const nb = join >> 1, nx = nb % BW * BS, ny = ((nb / BW) | 0) * BS;
|
||||
if (blockP[nb] === BP_BELT || blockP[nb] === BP_FILTER) return (ny - 1) * W + xx;
|
||||
if (blockP[nb] === BP_SCREW) {
|
||||
const v = blockV[nb];
|
||||
if (v >= 4) return yy * W + xx;
|
||||
if (v & 1) return (ny + (y & 3)) * W + xx;
|
||||
return (ny + (dy > 0 ? 0 : 3)) * W + nx + (y & 3);
|
||||
}
|
||||
}
|
||||
if (IS_SCREW[part[y * W + xx]]) return y * W + xx;
|
||||
if (dy > 0 && yy < H && (mat[yy * W + xx] === BELTL || mat[yy * W + xx] === BELTR)) return ((yy & ~3) - 1) * W + xx;
|
||||
const hy = by + (dy > 0 ? BS : -1), hx = bx + (y & 3);
|
||||
if (hy >= 0 && hy < H && IS_SCREW[part[hy * W + hx]]) return hy * W + hx;
|
||||
// An open mouth discharges along the diagonal, clear of the last block.
|
||||
// A corner screw is a separate end, not an open discharge cell.
|
||||
return yy >= 0 && yy < H && !IS_SCREW[part[yy * W + xx]] ? yy * W + xx : -1;
|
||||
}
|
||||
|
||||
+28
-9
@@ -90,16 +90,32 @@ function entScrewTick(e, p) {
|
||||
if ((tick & 1) || netSat(ci) <= 0 || rnd() > netSat(ci)) return;
|
||||
const dx = SCREW_DX[p], dy = SCREW_DY[p];
|
||||
if (dx && dy) { entDiagonalScrewTick(e, p); return; }
|
||||
const frontX = e.ix + (dx > 0 ? BAR_W - 1 : 0), frontY = e.iy + (dy > 0 ? BAR_H - 1 : 0);
|
||||
const front = frontY * W + frontX, dest = straightScrewNext(front, p);
|
||||
if (dest < 0) return;
|
||||
if (dest !== front + dx + dy * W) {
|
||||
const q = part[dest];
|
||||
if (!screwAccepts(q, dx, dy)) return;
|
||||
const x = (dest % W) & ~3, y = entScrewLane((dest / W) | 0, e.iy);
|
||||
if (entScrewMove(e, x, y, true)) stats.moved++;
|
||||
return;
|
||||
}
|
||||
let x = e.ix + dx, y = e.iy + dy, next = 0, ax = 0, ay = 0;
|
||||
for (let k = 0; k < (dx ? BAR_H : BAR_W); k++) {
|
||||
const i = entScrewEdge(e, dx, dy, k);
|
||||
if (i < 0) return;
|
||||
const xx = i % W, yy = (i / W) | 0;
|
||||
const q = part[i];
|
||||
if (IS_SCREW[q] && q !== p) { next = q; ax = xx; ay = yy; break; }
|
||||
if (IS_SCREW[q] && q !== p) {
|
||||
if (SCREW_DX[q] && SCREW_DY[q]) {
|
||||
const join = endJoin(frontX >> 2, frontY >> 2, dx + dy > 0 ? 1 : 0);
|
||||
if (join < 0 || (join >> 1) !== (yy >> 2) * BW + (xx >> 2)) return;
|
||||
}
|
||||
next = q; ax = xx; ay = yy; break;
|
||||
}
|
||||
}
|
||||
if (next) {
|
||||
if (SCREW_DX[next] === -dx && SCREW_DY[next] === -dy) return;
|
||||
if (!screwAccepts(next, dx, dy)) return;
|
||||
x = ax & ~3; y = entScrewLane(ay, e.iy);
|
||||
if (entScrewMove(e, x, y, true)) stats.moved++;
|
||||
return;
|
||||
@@ -115,17 +131,20 @@ function entScrewTick(e, p) {
|
||||
function entDiagonalScrewTick(e, p) {
|
||||
if (tick & 7) return;
|
||||
const dx = SCREW_DX[p], dy = SCREW_DY[p], bx = e.ix & ~3, by = e.iy & ~3, lane = e.iy & 3;
|
||||
for (const [ox, oy] of [[dx, dy], [dx, 0], [0, dy]]) {
|
||||
const x = bx + ox * BS, y = by + oy * BS + lane, q = entScrewAt(x, y);
|
||||
if (!q || (ox && oy && (q < P_SCREW_UR || q > P_SCREW_UL || SCREW_DX[q] !== dx || SCREW_DY[q] !== dy))) continue;
|
||||
const edge = (by + lane) * W + bx + (dx > 0 ? BS - 1 : 0);
|
||||
const dest = diagonalScrewNext(edge, p);
|
||||
if (dest < 0) return;
|
||||
const x = (dest % W) & ~3;
|
||||
let y = (dest / W) | 0;
|
||||
const q = part[dest];
|
||||
if (IS_SCREW[q]) {
|
||||
if (SCREW_DX[q] * dx + SCREW_DY[q] * dy < 0) return;
|
||||
y = Math.min((y & ~3) + BS - BAR_H, y);
|
||||
if (entScrewMove(e, x, y, true)) stats.moved++;
|
||||
return;
|
||||
}
|
||||
const x = bx + dx * BS;
|
||||
let y = by + dy * BS + lane;
|
||||
const belt = y >= 0 && y < H ? mat[y * W + x] : EMPTY;
|
||||
if (dy > 0 && (belt === BELTL || belt === BELTR)) y = (y & ~3) - BAR_H;
|
||||
const join = endJoin(bx >> 2, by >> 2, dx > 0 ? 1 : 0);
|
||||
if (join >= 0 && (blockP[join >> 1] === BP_BELT || blockP[join >> 1] === BP_FILTER)) y -= BAR_H - 1;
|
||||
if (!entScrewFree(x, y)) return;
|
||||
for (let yy = y; yy < y + BAR_H; yy++) for (let xx = x; xx < x + BAR_W; xx++) if (part[yy * W + xx]) return;
|
||||
if (entScrewMove(e, x, y, false, dy < 0)) { e.vx = dx * 0.5; e.vy = dy * 0.6; stats.moved++; }
|
||||
|
||||
@@ -97,7 +97,7 @@ function machinesTick() {
|
||||
// beat as belts (every other tick), so a block-wide screw carries as much as a block-deep belt
|
||||
if ((tick & 1) === 0) for (let p = 1; p < IS_SCREW.length; p++) {
|
||||
if (!IS_SCREW[p]) continue;
|
||||
const list = screwLists[p], dx = SCREW_DX[p], dy = SCREW_DY[p], dj = dy * W + dx, flat = dy === 0;
|
||||
const list = screwLists[p], dx = SCREW_DX[p], dy = SCREW_DY[p], flat = dy === 0;
|
||||
for (let k = 0; k < list.length; k++) {
|
||||
const i = list[k];
|
||||
if (part[i] !== p || occ[i]) continue;
|
||||
@@ -130,14 +130,14 @@ function machinesTick() {
|
||||
if (shifted) continue;
|
||||
}
|
||||
if (x + dx < 0 || x + dx >= W || y + dy < 0 || y + dy >= H) continue;
|
||||
const dest = dx && dy ? diagonalScrewNext(i, p) : i + dj;
|
||||
const dest = dx && dy ? diagonalScrewNext(i, p) : straightScrewNext(i, p);
|
||||
if (dest < 0) continue;
|
||||
const nx = dest % W, ny = (dest / W) | 0;
|
||||
if (nx < 0 || ny < 0 || nx >= W || ny >= H) continue;
|
||||
const j = dest;
|
||||
if (occ[j]) continue;
|
||||
const pj = part[j], screw = IS_SCREW[pj];
|
||||
if (screw && SCREW_DX[pj] === -dx && SCREW_DY[pj] === -dy) continue;
|
||||
if (screw && !screwAccepts(pj, dx, dy)) continue;
|
||||
const t = mat[j];
|
||||
if (!roomFor(j)) continue;
|
||||
if (pj === P_GRATE || pj === P_INTAKE || (pj === P_FILTER && !filterPassAt(m, j))) continue;
|
||||
|
||||
+4
-3
@@ -110,7 +110,7 @@ function drawPreviews() {
|
||||
if (dd !== GAME.dragDir) { GAME.dragDir = dd; hudDirty = true; }
|
||||
const dIdx = dd >= 0 ? dd : (GAME.pieceDir[P.id] || 0);
|
||||
const afford = canAfford(pieceCostNow(P), cells.length);
|
||||
const planned = (code === BP_SCREW && dIdx >= 4) || isSlopeBelt(code) ? new Map(cells.map(([x, y]) => [y * BW + x, [code, dIdx]])) : null;
|
||||
const planned = code === BP_SCREW || isSlopeBelt(code) ? new Map(cells.map(([x, y]) => [y * BW + x, [code, dIdx]])) : null;
|
||||
for (const [bx, by] of cells) {
|
||||
const err = canPlaceBlock(bx, by, code), rb = by * BW + bx;
|
||||
const swap = GAME.replace && !!blockP[rb] && /already built/.test(err) && !blockIs(rb, code, v, pieceExtra(P));
|
||||
@@ -180,12 +180,13 @@ function drawPreviews() {
|
||||
|
||||
function previewBlock(code, x, y, w, h, stroke = false, direction = -1, bx = -1, by = -1, planned = null) {
|
||||
const ctx = R.ctx;
|
||||
if (code === BP_SCREW && direction >= 4) {
|
||||
const joins = bx >= 0 ? diagonalScrewJoins(bx, by, direction, planned) : 0;
|
||||
if (code === BP_SCREW && (direction >= 4 || (bx >= 0 && straightScrewJoins(bx, by, direction, planned)))) {
|
||||
const joins = bx >= 0 ? (direction >= 4 ? diagonalScrewJoins(bx, by, direction, planned) : straightScrewJoins(bx, by, direction, planned)) : 0;
|
||||
const scale = w / BS, step = SET.look === "smooth" ? 0.25 : 1;
|
||||
const b = bx >= 0 ? by * BW + bx : 0, ox = (b % BW) * BS, oy = ((b / BW) | 0) * BS;
|
||||
ctx.beginPath();
|
||||
for (let yy = -4; yy < 8; yy += step) for (let xx = -4; xx < 8; xx += step) {
|
||||
if (direction < 4 && ((direction & 1) ? xx < 0 || xx >= BS : yy < 0 || yy >= BS)) continue;
|
||||
const sd = diagonalScrewShape(ox + xx + step / 2, oy + yy + step / 2, b, direction, joins);
|
||||
if (sd <= 0 && (!stroke || sd > -step * 1.5)) ctx.rect(x + xx * scale, y + yy * scale, step * scale, step * scale);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user