"""t45: real transport warnings, hover, frozen animation and recovery in both looks.""" import pathlib import sys sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1] / 'tools')) from use_venv import ensure_playwright; ensure_playwright() from browser import launch, consume_gpu_option consume_gpu_option() ROOT = pathlib.Path(__file__).resolve().parents[1] with launch(viewport={'width': 1280, 'height': 760}, page_path=sys.argv[1] if len(sys.argv)>1 else None) as (_, page, url): errors=[] page.on('pageerror', lambda e: errors.append(str(e))) page.goto(url) page.evaluate("""() => { const enter=enterGame;enterGame=()=>{enter();GAME.paused=true;}; SET.look='pixel';SET.workerCap=0;SET.autosave=0;startNewWorld(7,768,600); }""") page.wait_for_function('GAME.running', timeout=60000) page.evaluate("""() => { mat.fill(EMPTY);part.fill(0);blockP.fill(0);blockV.fill(0);isPow.fill(0); flags.fill(0);temp.fill(20);AMB.fill(20);bgm.fill(0);fog.fill(255); machines=[null];molds=[];ents=[];flyers=[];treeBases=[];saplings=[]; pcells.clear();beltL=[];beltR=[];screwLists=Array.from({length:IS_SCREW.length},()=>[]); weather.next=1e15;weather.shower=null;surfY.fill(300);updateRoof(); bot.x=320;bot.y=210;money=500;ledger={};nextPowerBuild=0; for(const [code,v,by] of [[BP_BELT,1,46],[BP_FILTER,128,52],[BP_SCREW,1,58]]) { for(let bx=68;bx<86;bx++)placeBlock(code,v,bx,by,true,{m:[],inv:0}); // The return screw hangs just above the loaded belt. if(code===BP_BELT)for(let bx=70;bx<86;bx++)placeBlock(BP_SCREW,3,bx,44,true); for(let y=by*4-4;ye.remove());R.floaters=[]; resizeRender();snapCamera();renderDirty.fill(1);GPU.world=null;SM.surf=-1; }""") assert page.evaluate("hoverInfo(330,185).warn==='stalled'"), 'jam has no hover warning' assert page.evaluate("hoverInfo(330,185).t2.some(t=>t.includes('Clear the outlet or the top of the heap'))") assert page.evaluate("[46,52,58].every(by=>transportStalled(by*BW+82))") for look in ['pixel','smooth']: page.evaluate(f"SET.look='{look}'") page.wait_for_function(f"R.smoothOn === {'true' if look=='smooth' else 'false'}") page.wait_for_timeout(150) assert page.evaluate("""() => { const p=worldToScreenPx(330,185),ctx=R.ctx; ctx.clearRect(0,0,R.canvas.width,R.canvas.height);drawTransportStalls(); const shown=ctx.getImageData(p.x,p.y,1,1).data[3]; SET.fog=true;fog.fill(0);ctx.clearRect(0,0,R.canvas.width,R.canvas.height);drawTransportStalls(); const hidden=ctx.getImageData(p.x,p.y,1,1).data[3];SET.fog=false;fog.fill(255); return shown>0 && hidden===0; }""") # Compare actual built pixels while simulation time advances under the jam. page.wait_for_timeout(60) clips=page.evaluate("""() => [184,208,233].map(y=>{const p=worldToScreenPx(329,y);return {x:p.x,y:p.y,width:18,height:9};})""") before=[page.screenshot(clip=c) for c in clips] page.evaluate('for(let k=0;k<10;k++)simTick()') page.wait_for_timeout(60) assert [page.screenshot(clip=c) for c in clips]==before, f'{look}: stalled transport still animates' path=ROOT / ('shots/t45-stalled.png' if look=='pixel' else 'shots/t45-stalled-smooth.png') page.screenshot(path=str(path)) print(f'PASS {look}: marker with overlay off, fog, hover, frozen rendered belt and screenshot') page.evaluate("""() => { for(const by of [46,52,58])for(let y=by*4-8;y