"""t69 only: both looks, persistent damage, hover, first message and real click/G repair.""" 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}) 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.cameraLead=false;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);bgm.fill(0);fog.fill(255); machines=[null];molds=[];ents=[];flyers=[];treeBases=[];saplings=[]; pcells.clear(); weather.next=1e15;weather.shower=null;surfY.fill(300);updateRoof(); bot.x=310;bot.y=210;bot.vx=bot.vy=0; money=500; ledger={}; for(let bx=72;bx<=84;bx++) placeBlock(BP_SCREW,1,bx,52,true); for(let x=288;x<340;x++)for(let y=209;y<212;y++)setCell(y*W+x,RBAS,20,0); for(let x=304;x<316;x++)for(let y=209;y<212;y++)temp[y*W+x]=950; // Melt the right section with the real machine tick, keeping the scene paused. for(let k=0;k<400;k++) { for(let x=328;x<340;x++)for(let y=208;y<212;y++) {const i=y*W+x;mat[i]=RBAS;temp[i]=1100;stamp[i]=0;} tick=2;tickStamp=2;machinesTick(); } for(let x=288;x<340;x++)for(let y=208;y<212;y++)temp[y*W+x]=x>=304&&x<316?950:20; document.querySelectorAll('.card-pop,.toast').forEach(e=>e.remove()); SET.cardSeconds=-1;drainEvents();R.floaters=[]; SET.fog=false;SET.zoom=12;SET.lighting='off';SET.glow='off';SET.minimap=false; SET.cursorLabel='all';GAME.infoOverlay=false;GAME.hidePreviews=true; resizeRender();snapCamera();renderDirty.fill(1);GPU.world=null;SM.surf=-1; }""") assert page.get_by_text('Screw conveyor melted', exact=True).is_visible() assert page.evaluate("hoverInfo(330,210).t2.join(' ').includes('hotter than 1000°C')") assert page.evaluate("hoverInfo(310,210).warn==='near heat limit'") assert page.evaluate("!hoverInfo(290,210).warn") 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) # The new overlay must alter pixels in both looks, and hide behind unexplored fog. assert page.evaluate("""() => { const sample=()=>{const p=worldToScreenPx(330,210);return Array.from(R.ctx.getImageData(p.x,p.y,1,1).data);}; R.ctx.clearRect(0,0,R.canvas.width,R.canvas.height); drawScrewHeat(); const shown=sample()[3];SET.fog=true;fog.fill(0); R.ctx.clearRect(0,0,R.canvas.width,R.canvas.height);drawScrewHeat(); const hidden=sample()[3]; SET.fog=false;fog.fill(255); return shown>0 && hidden===0; }""") page.wait_for_timeout(100) page.screenshot(path=str(ROOT / f'shots/t69-{look}.png')) print(f'PASS {look}: cold / warning / cooled melt damage, hover, fog and screenshot') # Exercise the actual build input, then undo, then G + click on the same cooled damage. page.evaluate("GAME.paused=false;devPaused=true;GAME.hidePreviews=false;GAME.tool=2;GAME.pieceIdx=PIECES.findIndex(p=>p.id==='screw');GAME.pieceDir.screw=1") target = page.evaluate("worldToScreenPx(330,210)") for replace in [False, True]: if replace: page.keyboard.down('g') before = page.evaluate('money') page.mouse.move(target['x'], target['y']) page.wait_for_timeout(60) page.mouse.click(target['x'], target['y']) page.wait_for_timeout(100) assert page.evaluate('blockIntegrity(52*BW+82)===16') assert page.evaluate('money') == before - 25 if replace: page.keyboard.up('g') page.keyboard.press('Control+z') assert page.evaluate('blockIntegrity(52*BW+82)<16') assert page.evaluate('money') == before assert not errors, errors print('PASS first melt message; real click and G repair at full cost; keyboard undo; no page errors')