121 lines
7.2 KiB
Python
121 lines
7.2 KiB
Python
"""t89: exact mouse pointers, open aim centres, menus and both-look cursor captures."""
|
|
import pathlib, 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]
|
|
fails = []
|
|
def check(name, ok):
|
|
print(('PASS ' if ok else 'FAIL ') + name)
|
|
if not ok: fails.append(name)
|
|
|
|
with launch(viewport={'width': 1280, 'height': 760}) as (_, page, url):
|
|
errors = []
|
|
page.on('pageerror', lambda e: errors.append(str(e)))
|
|
page.goto(url)
|
|
page.wait_for_function('CAPS.ready')
|
|
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)
|
|
check('game has an exact mouse pointer drawing pass', page.evaluate("typeof drawToolCursor === 'function'"))
|
|
if not fails:
|
|
page.evaluate("""() => {
|
|
SET.fog=false; SET.minimap=false; SET.zoom=6; SET.shake=false;
|
|
SET.lighting='off'; SET.glow='off'; devPaused=true; GAME.paused=false;
|
|
mat.fill(EMPTY); bgm.fill(0); part.fill(0); mach.fill(0); blockP.fill(0);
|
|
machines=[null]; molds=[]; ents=[]; flyers=[]; treeBases=[]; saplings=[];
|
|
surfY.fill(260); dirtY.fill(268); fog.fill(255);
|
|
for(let y=260;y<H;y++) for(let x=0;x<W;x++) setCell(y*W+x,STONE,20,F_NAT);
|
|
bot.x=320; bot.y=220; bot.vx=bot.vy=0;
|
|
bag[RSTONE]=500; bagTotal=500; money=5000;
|
|
GAME.pieceIdx=PIECES.findIndex(p=>p.id==='wall');
|
|
document.querySelectorAll('.card-pop,.toast').forEach(e=>e.remove());
|
|
resizeRender(); snapCamera(); GPU.world=null; SM.surf=-1;
|
|
}""")
|
|
page.mouse.move(711, 343)
|
|
# Capture only this pass on a transparent canvas to check the actual raster,
|
|
# independent of the world, grid and brush previews underneath it.
|
|
page.evaluate("""() => {
|
|
window.cursorRaster = () => {
|
|
const old=R.ctx, c=document.createElement('canvas');
|
|
c.width=R.canvas.width; c.height=R.canvas.height; R.ctx=c.getContext('2d');
|
|
try { drawToolCursor(); } finally { R.ctx=old; }
|
|
const u=R.canvas.width/innerWidth, x=Math.round(GAME.mouse.x*u), y=Math.round(GAME.mouse.y*u);
|
|
const ctx=c.getContext('2d'), data=ctx.getImageData(0,0,c.width,c.height).data;
|
|
let n=0; for(let i=3;i<data.length;i+=4) if(data[i]) n++;
|
|
const centre=ctx.getImageData(x-1,y-1,3,3).data;
|
|
return {n, open:!centre.some((v,i)=>i%4===3 && v),
|
|
nearby:ctx.getImageData(x-18*u,y-18*u,40*u,40*u).data.some((v,i)=>i%4===3 && v)};
|
|
};
|
|
window.cursorCalls=0; const draw=drawToolCursor;
|
|
drawToolCursor=()=>{cursorCalls++;draw();};
|
|
}""")
|
|
for look in ['pixel', 'smooth']:
|
|
page.evaluate('look => SET.look=look', look)
|
|
page.wait_for_function(f"R.smoothOn === {'true' if look == 'smooth' else 'false'}")
|
|
for name, key in [('drill','1'), ('nozzle','2'), ('build','3'), ('igniter','4'), ('copy','c'), ('cut','x'), ('paste','v')]:
|
|
page.evaluate('() => {keys.clear();GAME.paste=false;GAME.selDrag=null;GAME.drag=null;GAME.rmb=false;}')
|
|
if name == 'paste':
|
|
page.evaluate('GAME.clip={bw:2,bh:1,blocks:[[0,0,BP_WALL,RSTONE],[1,0,BP_WALL,RSTONE]],machines:[],molds:[]}')
|
|
if name in ['copy','cut']: page.keyboard.down(key)
|
|
else: page.keyboard.press(key)
|
|
page.wait_for_timeout(100)
|
|
if name != 'drill':
|
|
raster=page.evaluate('cursorRaster()')
|
|
check(f'{look} {name}: visible at mouse with open centre', raster['n'] > 0 and raster['open'] and raster['nearby'])
|
|
page.screenshot(path=str(ROOT / f'shots/t89-{look}-{name}.png'))
|
|
if name in ['copy','cut']: page.keyboard.up(key)
|
|
page.evaluate('cursorCalls=0')
|
|
page.wait_for_function('cursorCalls > 2')
|
|
check(f'{look}: pointer is called by real frame loop', page.evaluate('cursorCalls > 2'))
|
|
page.keyboard.press('Escape') # stop paste
|
|
page.evaluate("SET.look='pixel'")
|
|
page.wait_for_function('!R.smoothOn')
|
|
page.keyboard.press('2')
|
|
page.mouse.move(1100,343)
|
|
page.mouse.down(button='right')
|
|
check('distant blowing keeps pointer at mouse beyond nozzle reach', page.evaluate('!inReach(GAME.aim.x,GAME.aim.y) && cursorRaster().nearby && cursorRaster().open'))
|
|
page.screenshot(path=str(ROOT / 'shots/t89-pixel-nozzle-blow.png'))
|
|
page.mouse.up(button='right')
|
|
page.mouse.move(711,343)
|
|
page.keyboard.press('3')
|
|
page.mouse.down(); page.mouse.move(785, 367, steps=5)
|
|
check('build drag retains pointer and line', page.evaluate('!!GAME.drag && cursorRaster().n>0'))
|
|
page.screenshot(path=str(ROOT / 'shots/t89-pixel-build-drag.png'))
|
|
page.mouse.up()
|
|
for key, name in [('c','copy'),('x','cut')]:
|
|
page.keyboard.down(key)
|
|
page.mouse.move(711,343); page.mouse.down(); page.mouse.move(785,367,steps=5)
|
|
check(f'{name} drag retains pointer',page.evaluate('!!GAME.selDrag && cursorRaster().n>0'))
|
|
page.screenshot(path=str(ROOT / f'shots/t89-pixel-{name}-drag.png'))
|
|
page.mouse.up(); page.keyboard.up(key)
|
|
page.keyboard.press('Escape') # stop pasting the cut pieces
|
|
for zoom in [2,12]:
|
|
page.evaluate('zoom=>{SET.zoom=zoom;resizeRender();snapCamera();}',zoom)
|
|
page.mouse.move(711,440)
|
|
check(f'zoom {zoom}: pointer remains small with open aim',page.evaluate('cursorRaster().open && cursorRaster().n>0 && cursorRaster().n<250'))
|
|
page.screenshot(path=str(ROOT / f'shots/t89-pixel-build-zoom{zoom}.png'))
|
|
page.locator('.bb-tile').first.hover()
|
|
check('build menu keeps native pointer', page.locator('.bb-tile').first.evaluate("e=>getComputedStyle(e).cursor==='pointer'"))
|
|
check('game pointer hides over menu', page.evaluate('cursorRaster().n===0'))
|
|
page.mouse.move(711,343)
|
|
page.keyboard.press('Escape')
|
|
page.wait_for_function("document.body.classList.contains('paused')")
|
|
check('pause hides custom pointer', page.evaluate('cursorRaster().n===0'))
|
|
check('canvas behind menu has system pointer', page.locator('#game').evaluate("e=>getComputedStyle(e).cursor==='default'"))
|
|
page.screenshot(path=str(ROOT / 'shots/t89-menu.png'))
|
|
page.keyboard.press('Escape')
|
|
page.mouse.move(711,343)
|
|
page.evaluate('GAME.usingPad=true')
|
|
check('gamepad does not get a second mouse pointer', page.evaluate('cursorRaster().n===0'))
|
|
for scale in [1,2]:
|
|
page.evaluate('scale=>{GAME.usingPad=false;R.canvas.width=innerWidth*scale;R.canvas.height=innerHeight*scale;}',scale)
|
|
check(f'canvas scale {scale}: exact mouse pointer', page.evaluate('cursorRaster().nearby && cursorRaster().open'))
|
|
check('no page errors', not errors)
|
|
print('FAILS:', fails)
|
|
sys.exit(bool(fails))
|