// t69: melt feedback, full-cost repair without disturbing the load, and repair undo. const {load, suite, flatWorld} = require('./harness'); const {run} = load(), {check, done} = suite(); flatWorld(run, 160, 120, 100); run(`bot.x=40; bot.y=40; money=500; ledger={}; EV.length=0; placeBlock(BP_SCREW, 4, 10, 10, true); part[40*W+40]=0; markPow(40*W+40,false); setCell(40*W+40,RBAS,950,0);`); check('same screw builds over damage at full price', run(`undoRecord('repair',()=>placeBlocks(BP_SCREW,4,[[10,10]],null,false)).n===1 && money===475 && blockIntegrity(10*BW+10)===16`)); check('repair keeps the hot load in place', run('mat[40*W+40]===RBAS && temp[40*W+40]===950')); run('undoLast()'); check('undo restores the hole and refunds repair cost', run('part[40*W+40]===0 && !isPow[40*W+40] && money===500 && blockIntegrity(10*BW+10)===15')); check('G also repairs without a removal refund', run(`undoRecord('repair',()=>placeBlocks(BP_SCREW,4,[[10,10]],null,true)).n===1 && money===475`)); check('G over an intact screw costs nothing', run('placeBlocks(BP_SCREW,4,[[10,10]],null,true).n===0 && money===475')); run('part[40*W+40]=0; money=0'); check('unaffordable repair leaves the damage alone', run('!!placeBlock(BP_SCREW,4,10,10,false) && part[40*W+40]===0 && money===0')); run(`money=500; placeBlock(BP_SCREW,4,10,10,false); tick=2; tickStamp=2; for(const i of blockCellList(10,10)) {setCell(i,RBAS,1000,0);} rebuildPower(); for(let k=0;k<500;k++) { for(const i of blockCellList(10,10)) {mat[i]=RBAS; stamp[i]=0;} machinesTick(); }`); check('1000 degrees does not melt screws', run('blockIntegrity(10*BW+10)===16')); run(`for(const i of blockCellList(10,10)) temp[i]=1100; for(let k=0;k<500;k++) { for(const i of blockCellList(10,10)) {mat[i]=RBAS; stamp[i]=0;} machinesTick(); }`); check('hot loads still melt cell by cell', run('blockIntegrity(10*BW+10)<16')); check('first melt explains heat limit and repair once', run(`EV.filter(e=>e.t==='screw_melt').length===1 && ledger.screwMelt===true`)); run('const heatSave=serializeWorld(); deserializeWorld(heatSave.meta,heatSave.buffers)'); check('existing save data retains damage and first-message state', run('blockIntegrity(10*BW+10)<16 && ledger.screwMelt===true')); run(`placeBlock(BP_SCREW,4,10,10,true); for(const i of blockCellList(10,10)) {mat[i]=EMPTY; temp[i]=1100;} setCell(41*W+41,RBAS,899,0);`); check('empty hot cells do not count as a hot load', run('screwLoadHeat(10*BW+10)===899')); run('temp[41*W+41]=900'); check('warning can start before the melt limit', run('screwLoadHeat(10*BW+10)===900 && blockIntegrity(10*BW+10)===16')); run('part[40*W+40]=0; ghostBlocks.set(10*BW+10,[BP_SCREW,4,null,1]); money=500; ghostTick()'); check('a queued G repair restores damage without refunding', run('blockIntegrity(10*BW+10)===16 && money===475 && !ghostBlocks.size')); run(`part[40*W+40]=0; money=500; undoRecord('queued repair',()=>{ghostBlocks.set(10*BW+10,[BP_SCREW,4,null,1]);undoNote({t:'paste',blocks:[[10,10,BP_SCREW,1]],machines:[],molds:[]});}); ghostTick();undoLast();`); check('undo of a completed queued repair preserves the original damaged screw',run('blockP[10*BW+10]===BP_SCREW && blockIntegrity(10*BW+10)===15 && money===500')); for(let v=0;v<8;v++) { run(`removeBlock(10,10);placeBlock(BP_SCREW,${v},10,10,true); part[40*W+40]=0; markPow(40*W+40,false); placeBlock(BP_SCREW,${v},10,10,true)`); check(`repair restores direction ${v}`,run(`part[40*W+40]===SCREW_PARTS[${v}] && blockIntegrity(10*BW+10)===16`)); } done();