The lake lip was Math.min(surfY), the highest ground (y grows downward), so water was poured above the lower rim and, once levelled, ran up to the trade dock on 4 of 12 seeds. The lip is now the lower rim edge minus one, and each lake stays 80 grains from spawn. Seed hashes and the shallow-ore hash re-baselined (changes only under lake basins); golden fixtures also freeze surfY/dirtY/AMB from the previous generator. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
56 lines
3.0 KiB
Python
56 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
"""t96: flat generated lakes, fresh and reloaded, in the real pixel frame loop."""
|
|
import sys
|
|
from pathlib import Path
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(ROOT / 'tools'))
|
|
from use_venv import ensure_playwright
|
|
ensure_playwright()
|
|
from browser import launch
|
|
errors = []
|
|
with launch(viewport={'width':1280,'height':760}) as (_, pg, url):
|
|
pg.on('pageerror', lambda e: errors.append(str(e)))
|
|
pg.goto(url)
|
|
pg.evaluate('CAPS_CHECK')
|
|
pg.evaluate('''() => { SET.workerCap=2; SET.fog=false; SET.look='pixel'; SET.autosave=0; SET.cameraLead=false;
|
|
const enter=enterGame; enterGame=function(){enter();GAME.paused=true;}; }''')
|
|
pg.evaluate('startNewWorld(7,2048,1024)')
|
|
pg.wait_for_function('GAME.running',timeout=60000)
|
|
pg.evaluate('''() => { weather.next=1e15; SET.zoom=3; resizeRender(); bot.x=880;bot.y=275; snapCamera();
|
|
document.querySelectorAll('.card,.toast').forEach(e=>e.remove());$('hud').hidden=true;
|
|
globalThis.lakeSave=serializeWorld(); }''')
|
|
assert pg.evaluate('treeBases.every(i=>!treeHeld(i)||mat[i]!==WATER)')
|
|
assert pg.evaluate('mat.every((m,i)=>m!==WATER||awake[((i/W)>>5)*CW+((i%W)>>5)]>0)')
|
|
measure = '''() => { const pools=[]; let p=null;
|
|
for(let x=0;x<W;x++){let y=0;while(y<H&&mat[y*W+x]===EMPTY)y++;
|
|
if(mat[y*W+x]!==WATER){p=null;continue;}
|
|
if(!p){p={width:0,min:y,max:y};pools.push(p);}
|
|
p.width++;p.min=Math.min(p.min,y);p.max=Math.max(p.max,y);}
|
|
return pools.filter(p=>p.width>20); }'''
|
|
pools=pg.evaluate(measure)
|
|
print('fresh startup',pools,flush=True)
|
|
assert pools and all(p['max']-p['min']<=1 for p in pools)
|
|
pg.wait_for_timeout(300)
|
|
(ROOT/'shots').mkdir(exist_ok=True)
|
|
pg.screenshot(path=str(ROOT/'shots/t96-level.png'))
|
|
for state in ('fresh','reloaded'):
|
|
if state=='reloaded':
|
|
pg.evaluate('''() => {deserializeWorld(lakeSave.meta,lakeSave.buffers);weather.next=1e15;}''')
|
|
pg.evaluate('startThreads()')
|
|
for batch in range(3):
|
|
pg.evaluate('for(let k=0;k<200;k++)simTick();')
|
|
result=pg.evaluate('''() => {let lo=H,hi=0,n=0,wet=0;
|
|
for(let x=650;x<1100;x++){let y=0;while(y<H&&mat[y*W+x]===EMPTY)y++;
|
|
if(mat[y*W+x]===WATER){lo=Math.min(lo,y);hi=Math.max(hi,y);n++;}}
|
|
for(const i of treeBases)if(i%W>=650&&i%W<1100&&treeHeld(i)&&mat[i]===WATER)wet++;
|
|
return {lo,hi,n,wet,workers:simPool?.workers.length};}''')
|
|
pools=pg.evaluate(measure)
|
|
assert pools and all(p['max']-p['min']<=1 for p in pools),pools
|
|
print(state,result,pools,flush=True)
|
|
assert result['n']>150 and result['hi']-result['lo']<=1 and result['wet']==0
|
|
pg.evaluate('snapCamera();renderDirty.fill(1);')
|
|
pg.wait_for_timeout(300)
|
|
pg.screenshot(path=str(ROOT/f'shots/t96-{state}-settled.png'))
|
|
assert not errors,errors
|
|
print('PASS t96 pixel flat startup and 600-tick fresh/reloaded lakes, dry roots, 2 browser helpers, no page errors',flush=True)
|