Uphill runs share one cleat phase; no cleats downhill; pick slope bands
A piece added to a running sloped belt kept its own cleat phase, so at the seam a rib could start just behind another and push its pocket into it, stalling the whole run with only a few grains. Every block of a run now takes the phase of the run's lower-left block. Downhill sloped belts no longer have cleats: they carry like a flat belt (90 grains/s, was 38) and draw only the sidewall. Middle click on a sloped belt's band, where it is drawn into the empty block beside it, now picks the belt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -99,7 +99,7 @@ check('drawing leaves the seed, cells and saved block data unchanged', run(`(()
|
||||
})()`));
|
||||
for (const grade of [-1,1]) {
|
||||
flatWorld(run,160,120,112);
|
||||
run(`for(let k=0;k<6;k++)placeBlock(${grade<0?'BP_BELT_UP':'BP_BELT_DOWN'},1,12+k,${grade<0?20:12}+k*${grade},true);`);
|
||||
run(`for(let k=0;k<6;k++)placeBlock(${grade<0?'BP_BELT_UP':'BP_BELT_DOWN'},${grade<0?1:0},12+k,${grade<0?20:12}+k*${grade},true);`); // uphill, the cleated way
|
||||
for(let phase=0;phase<8;phase++) {
|
||||
run(`rebuildPower();slopePhase.fill(${phase});slopeCleatsTick(false);prepareSlopeBelts(0,0,W,H);`);
|
||||
check(`grade ${grade} phase ${phase} draws exactly the physical cleat raster`,run(`(()=>{
|
||||
|
||||
+26
-5
@@ -32,9 +32,8 @@ for(const grade of [0,-1,1]) {
|
||||
else {fresh();run('for(let bx=10;bx<32;bx++)placeBlock(BP_BELT,1,bx,24,true);');s={inlet:24};}
|
||||
collect(s,220,true);
|
||||
const r=collect(s,600,true);rates.push(r.out/10);
|
||||
// uphill pockets carry about as much as a flat belt; downhill, the top only feeds a layer two
|
||||
// grains deep onto the face, which the ribs hold back to belt speed
|
||||
const floor = grade > 0 ? 30 : 60;
|
||||
// uphill pockets carry about as much as a flat belt, and downhill runs like one
|
||||
const floor = 60;
|
||||
check(`grade ${grade} carries a generous feed at least ${floor} grains/s`,r.out>0 && r.out/10>=floor,JSON.stringify(r));
|
||||
const end=collect(s,600);
|
||||
check(`grade ${grade} leaves no load stuck`,end.left===0,JSON.stringify(end));
|
||||
@@ -114,7 +113,9 @@ for(const c of ['BP_BELT_UP','BP_BELT_DOWN','BP_FILTER_UP','BP_FILTER_DOWN'])for
|
||||
check(`${c} ${d} saves its shape, direction and settings`,run(`blockP[20*BW+20]===${c} && blockV[20*BW+20]===${c.includes('FILTER')?'filterVariant('+c+','+d+'*128)':d} && blockIntegrity(20*BW+20)===10 ${c.includes('FILTER')?'&& sameFilter(filterInfo(20*BW+20),{m:[SAND,BARCU].sort((a,b)=>a-b),inv:1})':''}`));
|
||||
if(c.includes('BELT')) {
|
||||
run(`slopePhase[20*BW+20]=${d?1:7};rebuildPower();slopeCleatsTick(false);globalThis.savedPhase=serializeWorld();deserializeWorld(savedPhase.meta,savedPhase.buffers);`);
|
||||
check(`${c} saves the moving cleat phase and immediately restores its barriers`,run(`slopePhase[20*BW+20]===${d?1:7} && cleatCells.length>0`));
|
||||
// only an uphill run has cleats
|
||||
const up=(c==='BP_BELT_UP')===(d===1);
|
||||
check(`${c} saves the moving cleat phase and immediately restores its barriers`,run(`slopePhase[20*BW+20]===${d?1:7} && cleatCells.length${up?'>0':'===0'}`));
|
||||
}
|
||||
run(`globalThis.clip=copyRegion(80,80,83,83);bot.x=96;bot.y=80;undoRecord('paste',()=>pasteGhost(clip,24,20));ghostTick();`);
|
||||
check(`${c} ${d} copy/paste keeps all settings`,run('blockP[20*BW+24]===blockP[20*BW+20] && blockV[20*BW+24]===blockV[20*BW+20] && sameFilter(filterInfo(20*BW+20),filterInfo(20*BW+24))'));
|
||||
@@ -160,11 +161,23 @@ run('placeBlock(BP_BELT_UP,1,20,32,true);');
|
||||
check('a grain on the bare face slides back down to a rib',g>0 && Math.min(...path)<g,JSON.stringify([g,path.slice(0,12)]));
|
||||
check('then rides up with its rib',path[path.length-1]>Math.min(...path),JSON.stringify(path.slice(-8)));
|
||||
}
|
||||
// A piece added to a running belt takes up its cleat spacing, so no rib starts at the seam and
|
||||
// pushes its pocket into the one ahead (that stalled the whole run).
|
||||
for(const wait of [3,7,11,13]){
|
||||
fresh();
|
||||
run(`for(let k=0;k<9;k++)placeBlock(BP_BELT_UP,1,16+k,40-k,true);for(let k=1;k<=6;k++)placeBlock(BP_BELT,1,16-k,41,true);
|
||||
for(let t=0;t<${wait};t++)simTick();
|
||||
for(let k=9;k<12;k++)placeBlock(BP_BELT_UP,1,16+k,40-k,true);for(let k=1;k<=6;k++)placeBlock(BP_BELT,1,27+k,29,true);`);
|
||||
const r=run(`(()=>{let added=0,past=0;for(let t=0;t<1500;t++){if(t<300&&t%10===0){const i=(41*4-1)*W+50;if(mat[i]===EMPTY){setCell(i,SAND,20,0);added++;}}simTick();}
|
||||
for(let i=0;i<N;i++)if(mat[i]===SAND&&i%W>=112)past++;return {added,past,same:slopePhase[32*BW+24]===slopePhase[31*BW+25]};})()`);
|
||||
check(`a piece added ${wait} ticks later shares the run's phase and the run keeps carrying`,r.same && r.added>0 && r.past===r.added,JSON.stringify(r));
|
||||
}
|
||||
// A stationary cleat blocks downhill crossings; the bare face still lets grains slide.
|
||||
for (const grade of [-1,1]) {
|
||||
const s=line(grade);
|
||||
run('rebuildPower();slopeCleatsTick(false);');
|
||||
check(`grade ${grade} cleats block every downhill crossing`,run(`cleatCells.length>0 && cleatCells.every(i=>!enter(SAND,PH_POWDER,i,${grade},1) && !enter(SAND,PH_POWDER,i+W+${grade},${grade},1))`));
|
||||
if(grade>0) check('a downhill run has no cleats',run('cleatCells.length===0'));
|
||||
else check(`grade ${grade} cleats block every downhill crossing`,run(`cleatCells.length>0 && cleatCells.every(i=>!enter(SAND,PH_POWDER,i,${grade},1) && !enter(SAND,PH_POWDER,i+W+${grade},${grade},1))`));
|
||||
check(`grade ${grade} bare face slides between steps without stamping the load`,run(`(()=>{
|
||||
for(let x=72;x<96;x++){
|
||||
const by=${s.by}+((x>>2)-16)*${grade}, y=beltFaceY(blockP[by*BW+(x>>2)],x>>2,by,x)-1,i=y*W+x;
|
||||
@@ -206,6 +219,14 @@ for(const id of ['belt','filter'])for(const [dx,dy] of [[3,-3],[3,3],[-3,3],[-3,
|
||||
check(`${id} a single replacement keeps the selected direction`,run(`blockP[${20+dy}*BW+${20+dx}]===${c} && blockV[${20+dy}*BW+${20+dx}]===${id==='filter'?v:1-v}`));
|
||||
|
||||
}
|
||||
// Middle click on the belt band you see, even where it is drawn into the empty block next door.
|
||||
fresh();
|
||||
const band=run(`(()=>{globalThis.R=globalThis.R||{smoothOn:false};
|
||||
for(let k=0;k<4;k++)placeBlock(BP_BELT_UP,1,20+k,24-k,true);prepareSlopeBelts(0,0,W,H);
|
||||
for(let y=60;y<110;y++)for(let x=70;x<100;x++){const i=y*W+x,own=(y>>2)*BW+(x>>2);
|
||||
if(!blockP[own] && mat[i]===EMPTY && slopeBeltAt(i,x,y)>=0){GAME.pieceIdx=PIECE_BY_ID.wall.index;GAME.aim={x:x+0.5,y:y+0.5};pickUnderCursor();return GAME.pieceIdx===PIECE_BY_ID.belt.index;}}
|
||||
return 'no band cell outside its block';})()`);
|
||||
check('middle click on a sloped belt band outside its block picks the belt',band===true,band);
|
||||
run(fs.readFileSync('src/ui/selection-pickers.js','utf8'));
|
||||
const filterLine=line(-1,true);
|
||||
run("applyFilterRun(filterRun(32*BW+16),{m:[GRAVEL],inv:1,dir:0});");
|
||||
|
||||
Reference in New Issue
Block a user