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:
+11
-1
@@ -681,7 +681,7 @@ with sync_playwright() as p:
|
||||
ev(f'bot.x = {x_before}; bot.y = {y_before}; R.snapNext = true;'); settle(200)
|
||||
# pipes are laid by dragging, like belts
|
||||
ok = select('3', "piece().id === 'pipe'")
|
||||
check('pipes, pumps, outlets and the refiner are in the build menu', ok and all(x in ev("PIECES.filter(p => !p.hidden).map(p => p.id)") for x in ['pipe', 'pump', 'outlet', 'refiner']))
|
||||
check('pipes, pumps, outlets and hoppers are in the build menu', ok and all(x in ev("PIECES.filter(p => !p.hidden).map(p => p.id)") for x in ['pipe', 'pump', 'outlet', 'grinder', 'saw']))
|
||||
ev(f"for (let y = {(bby+2)*4}; y < {(bby+3)*4}; y++) for (let x = {(bbx-8)*4}; x < {(bbx+4)*4}; x++) if (!blockP[((y/4)|0)*BW + ((x/4)|0)]) setCell(y*W+x, EMPTY, 20, 0);")
|
||||
drag(lambda: blk(bbx - 6, bby + 2), lambda: blk(bbx - 3, bby + 2))
|
||||
check('dragging lays a line of pipe that joins into one line', ev(f'(() => {{ let n = 0; for (let bx = {bbx} - 6; bx <= {bbx} - 3; bx++) if (blockP[({bby} + 2) * BW + bx] === BP_PIPE) n++; return n; }})()') == 4 and ev(f'pipeNetOf(({bby} + 2) * BW + {bbx} - 6).blocks.length') == 4, ev('GAME.status'))
|
||||
@@ -690,6 +690,16 @@ with sync_playwright() as p:
|
||||
pg.keyboard.press('Control+z'); settle(200)
|
||||
check('and Ctrl+Z swaps the belt back', ev(f'blockP[({bby} + 1) * BW + {bbx} - 4]') == ev('BP_BELT') and not ev(f"machines.some(m => m && m.type === 'fan' && m.x === ({bbx} - 4) * 4)"), ev('GAME.status'))
|
||||
|
||||
# 7a. hopper blocks: the Machines tab has Grinder and Saw instead of the Refiner and Stone cutter; drag a row
|
||||
check('the Machines tab has Grinder and Saw but not the Refiner or Stone cutter', ev("(() => { const ids = BUILD_CATS.find(c => c[0] === 'Machines')[1]; return ids.includes('grinder') && ids.includes('saw') && !ids.includes('refiner') && !ids.includes('cutter'); })()"))
|
||||
ev('money = 1000')
|
||||
ok = select('3', "piece().id === 'grinder'")
|
||||
ev(f"for (let y = {(bby+3)*4}; y < {(bby+4)*4}; y++) for (let x = {(bbx-8)*4}; x < {(bbx+4)*4}; x++) if (!blockP[((y/4)|0)*BW + ((x/4)|0)]) setCell(y*W+x, EMPTY, 20, 0);")
|
||||
drag(lambda: blk(bbx - 6, bby + 3), lambda: blk(bbx - 4, bby + 3))
|
||||
check('dragging a row of Grinders places three blocks', ok and ev(f'(() => {{ let n = 0; for (let bx = {bbx} - 6; bx <= {bbx} - 4; bx++) if (blockP[({bby} + 3) * BW + bx] === BP_GRIND) n++; return n; }})()') == 3, ev('GAME.status'))
|
||||
pg.keyboard.press('Control+z'); settle(200)
|
||||
check('Ctrl+Z takes the Grinder row back', ev(f'(() => {{ for (let bx = {bbx} - 6; bx <= {bbx} - 4; bx++) if (blockP[({bby} + 3) * BW + bx]) return false; return true; }})()'))
|
||||
|
||||
# 7b. filter: choose several materials with F, place a line, replace belts with G, edit the whole line
|
||||
ev('seen[CUORE] = 1; seen[FEORE] = 1; seen[SAND] = 1; money = 1000; GAME.filterCfg = { m: [], inv: 0 };')
|
||||
ok = select('3', "piece().id === 'filter'")
|
||||
|
||||
@@ -65,6 +65,41 @@ check('F shuts it again', count(run, run('RSTONE'), 100, 27, 120, 99) === out1);
|
||||
run('(() => { const s = serializeWorld(); deserializeWorld(JSON.parse(JSON.stringify(s.meta)), s.buffers); })()');
|
||||
check('what is in a silo is saved', run(`${silo}.sn`) === held - out1 && run(`${silo}.sm`) === run('RSTONE'));
|
||||
|
||||
// ---- block hoppers: feed the top edge, clear the outlet between jobs
|
||||
function hopper(code, stack = false) {
|
||||
flatWorld(run, 240, 160, 120);
|
||||
run(`money = 9999; stats.refined = 0; stats.bricks = 0; placeBlock(${code}, 0, 20, 18, true); ${stack ? 'placeBlock(BP_GRIND, 0, 20, 19, true);' : ''}`);
|
||||
}
|
||||
function feedHopper(m, n, bottom = 76) {
|
||||
run(`for (const e of ents.slice()) removeEnt(e);
|
||||
for (let k = 0; k < ${n}; k++) {
|
||||
for (let y = ${bottom}; y < ${bottom}+2; y++) for (let x = 80; x < 84; x++) setCell(y*W+x, EMPTY, 20, 0);
|
||||
setCell(71*W+80, ${m}, 60, 0); stamp[71*W+80] = 0;
|
||||
for (let t = 0; t < 4; t++) { tick++; tickStamp++; procBlocksTick(); }
|
||||
}`);
|
||||
}
|
||||
hopper('BP_SAW'); feedHopper('RSTONE', 8);
|
||||
check('a Saw cuts eight stone grains into one brick below', run('stats.bricks === 1 && ents[0].iy === 76'));
|
||||
feedHopper('CUORE', 1);
|
||||
check('a Saw passes other grains through at their temperature', run('mat[76*W+81] === CUORE && temp[76*W+81] === 60'));
|
||||
hopper('BP_SAW');
|
||||
run('for (let x = 80; x < 84; x++) setCell(76*W+x, STONE, 20, 0); setCell(71*W+80, RSTONE, 20, 0); stamp[71*W+80] = 0; for (let k = 0; k < 8; k++) { tick++; tickStamp++; procBlocksTick(); }');
|
||||
check('a full outlet stops a Saw before consuming stone', run('mat[71*W+80] === RSTONE && procState.get(18*BW+20).blocked'));
|
||||
hopper('BP_GRIND'); feedHopper('RSTONE', 200);
|
||||
check('a Grinder counts every ground grain and reduces rubble', run('stats.refined === 200') && count(run, run('RSTONE')) === 0);
|
||||
hopper('BP_GRIND');
|
||||
run('placeBlock(BP_GRIND, 0, 21, 18, true); for (let k = 0; k < 80; k++) { for (let x = 80; x < 88; x++) { setCell(71*W+x, GRAVEL, 20, 0); stamp[71*W+x] = 0; setCell(76*W+x, EMPTY, 20, 0); } tick++; tickStamp++; procBlocksTick(); }');
|
||||
check('two Grinders work twice one block rate', run('stats.refined === 40'), run('stats.refined'));
|
||||
hopper('BP_SAW', true); feedHopper('RSTONE', 8, 80);
|
||||
check('a Saw over a Grinder drops its brick under the stack', run('stats.bricks === 1 && ents[0].iy === 80'));
|
||||
feedHopper('GRAVEL', 40, 80);
|
||||
check('gravel passes through the Saw and is ground below', run('stats.refined === 40'));
|
||||
run('removeBlock(20, 18); removeBlock(20, 19);');
|
||||
check('removing hoppers refunds costs, clears cells and state', run('money === 10149 && mat[72*W+80] === EMPTY && mat[76*W+80] === EMPTY && procState.size === 0'));
|
||||
hopper('BP_SAW'); feedHopper('RSTONE', 3);
|
||||
run('(() => { const s = serializeWorld(); deserializeWorld(s.meta, s.buffers); })(); procBlocksTick();');
|
||||
check('loading rebuilds processors and drops partial brick state', run('procBlocks.length === 1 && procState.get(18*BW+20).cut === 0 && SAVE_VERSION === 2'));
|
||||
|
||||
// ---- builders' orders: bulk rubble, gravel and stone bricks at a few times a tiny price
|
||||
flatWorld(run, 240, 160, 100);
|
||||
run('seen[RSTONE] = 1; seen[GRAVEL] = 1; seen[BARSB] = 1; orders = []; ordersDone = 0;');
|
||||
|
||||
Reference in New Issue
Block a user