Grinder and Saw hopper blocks replace the Refiner and Stone cutter in the menu (t4)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -74,6 +74,72 @@ function cutterTick(mm) {
|
||||
jobs--; mm.busyT = tick;
|
||||
}
|
||||
}
|
||||
// Block hoppers share an outlet down a vertical stack; only its top spends work.
|
||||
let procState = new Map(), procBlocks = [], procDirty = true;
|
||||
function isProcCode(c) { return c === BP_GRIND || c === BP_SAW; }
|
||||
function rebuildProcessors() {
|
||||
procBlocks = [];
|
||||
for (let b = 0; b < NB; b++) if (isProcCode(blockP[b])) {
|
||||
procBlocks.push(b);
|
||||
if (!procState.has(b)) procState.set(b, { work: 0, cut: 0, busyT: -999, blocked: false });
|
||||
}
|
||||
procDirty = false;
|
||||
}
|
||||
function procBottom(b) { while (b + BW < NB && isProcCode(blockP[b + BW])) b += BW; return b; }
|
||||
function procSlot(b) {
|
||||
const y = (((b / BW) | 0) + 1) * BS, x = (b % BW) * BS;
|
||||
if (y >= H) return -1;
|
||||
for (let k = 0; k < 4; k++) { const j = y * W + x + [1, 2, 0, 3][k]; if (mat[j] === EMPTY && !part[j] && !occ[j] && !mach[j]) return j; }
|
||||
return -1;
|
||||
}
|
||||
function procFeed(b, m, T) {
|
||||
const end = procBottom(b), x = (b % BW) * BS, y = ((b / BW) | 0) * BS - 1;
|
||||
for (;;) {
|
||||
const s = procState.get(b); s.busyT = tick;
|
||||
if (blockP[b] === BP_GRIND && PH[m] === PH_POWDER && REFINE[m]) {
|
||||
const from = m; let got = 0;
|
||||
for (const [chance, o] of REFINE[m]) if (rnd() < chance) { got = o; break; }
|
||||
if (got) { stats.refinedOre = (stats.refinedOre || 0) + 1; discover(got, x, y, from, 'refine'); }
|
||||
else if (rnd() < REFINE_SAND) got = SAND;
|
||||
stats.refined = (stats.refined || 0) + 1; m = got;
|
||||
if (!m) return;
|
||||
} else if (blockP[b] === BP_SAW && m === RSTONE) {
|
||||
if (++s.cut < CUT_PER_BRICK) return;
|
||||
s.cut = 0; m = BARSB;
|
||||
}
|
||||
if (b === end) break;
|
||||
b += BW;
|
||||
}
|
||||
if (m === BARSB) {
|
||||
const e = spawnBar(BARSB, x, (((end / BW) | 0) + 1) * BS, (rnd() - 0.5) * 0.1, 0.05);
|
||||
if (e) { e.T = T; discover(BARSB, x, y, RSTONE, 'cut'); stats.bricks = (stats.bricks || 0) + 1; }
|
||||
} else setCell(procSlot(end), m, T, 0);
|
||||
}
|
||||
function procBlocksTick() {
|
||||
if (procDirty) rebuildProcessors();
|
||||
for (const b of procBlocks) {
|
||||
if (b >= BW && isProcCode(blockP[b - BW])) continue;
|
||||
const s = procState.get(b), end = procBottom(b), y = ((b / BW) | 0) * BS - 1, x = (b % BW) * BS;
|
||||
s.work += blockP[b] === BP_GRIND ? 0.25 : 0.5;
|
||||
let jobs = Math.floor(s.work); s.work -= jobs;
|
||||
if (!jobs || y < 0) continue; // a tick without work keeps the last blocked state, so it doesn't flicker
|
||||
for (let q = b; q <= end; q += BW) procState.get(q).blocked = false;
|
||||
for (let k = 0; k < 4 && jobs > 0; k++) {
|
||||
const i = y * W + x + ((k + tick) & 3), m = mat[i];
|
||||
if (m === EMPTY || PH[m] === PH_GAS || PH[m] === PH_SOLID || stamp[i] === tickStamp) continue;
|
||||
let brick = false;
|
||||
if (m === RSTONE) for (let q = b; q <= end; q += BW) {
|
||||
if (blockP[q] === BP_GRIND) break;
|
||||
if (blockP[q] === BP_SAW) { brick = procState.get(q).cut + 1 >= CUT_PER_BRICK; break; }
|
||||
}
|
||||
if (procSlot(end) < 0 || brick && !entFreeAt(x, (((end / BW) | 0) + 1) * BS)) {
|
||||
for (let q = b; q <= end; q += BW) procState.get(q).blocked = true;
|
||||
break;
|
||||
}
|
||||
const T = temp[i]; setCell(i, EMPTY, AMB[y], 0); procFeed(b, m, T); jobs--;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ---------- Silo ----------
|
||||
// One loose material, counted (not simulated grain by grain inside): grains in the roof hatch
|
||||
// go in, and with the gate open they come out of the bottom of the cone.
|
||||
|
||||
Reference in New Issue
Block a user