New claims: open another claim once one is paid off, travel between them (t3)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+89
-1
@@ -814,10 +814,98 @@ with sync_playwright() as p:
|
||||
await DB.op('readwrite', st => st.put({...s, savedAt: Date.now() + 1000, playTime: 4567}, `${id}:main`));
|
||||
const sv = await worldNewest(id);
|
||||
bagTotal = 0; worldSeed = 0;
|
||||
return startFromSave(sv) && worldSeed === s.meta.seed && GAME.playTime === 4567 &&
|
||||
return await startFromSave(sv) && worldSeed === s.meta.seed && GAME.playTime === 4567 &&
|
||||
bagTotal === s.meta.bag.reduce((n, v) => n + v, 0);
|
||||
}"""))
|
||||
|
||||
# Careers use their own browser storage so the play-through stays untouched.
|
||||
career_play_paused = ev('GAME.paused'); ev('GAME.paused = true')
|
||||
cc = b.new_context(viewport={'width': 1280, 'height': 800})
|
||||
cp = cc.new_page(); cp.on('pageerror', lambda e: logs.append(f'PAGEERROR: {e}'))
|
||||
cp.goto(url); cp.wait_for_function("!$('title').hidden")
|
||||
ev = cp.evaluate
|
||||
ev("async () => { SET.fog = false; await startNewWorld(424242, 512, 384, 'First claim'); GAME.paused = true; }")
|
||||
check('fresh world has a career with claim 1', ev("async () => { const c = await DB.get('career:' + GAME.careerId); return c.claimNo === 1 && c.claims.length === 1 && c.claims[0] === GAME.worldId && (await listWorlds())[0].claimNo === 1; }"))
|
||||
check('unpaid claim cannot open another', ev('async () => !await openNewClaim() && career.claims.length === 1'))
|
||||
ev("openNotebook('Claims')")
|
||||
cp.wait_for_function("$('nb-body').textContent.includes('paid off.')")
|
||||
check('Claims explains the unpaid requirement', ev("!$('claim-open') && $('nb-body').textContent.includes('Machines on other claims wait')"))
|
||||
ev("debt = 0; money = 4999; renderNotebook()")
|
||||
cp.wait_for_function("$('claim-open') && $('claim-open').disabled")
|
||||
check('Claims disables opening without the down payment', ev("$('claim-open').disabled && $('nb-body').textContent.includes('You need $5,000')"))
|
||||
check('insufficient funds cannot open another claim', ev('async () => !await openNewClaim() && money === 4999'))
|
||||
ev("""() => {
|
||||
money = 10000; earned = 12345; bag.fill(0); bag[RSTONE] = 91; bag[COAL] = 13; bagTotal = 104;
|
||||
player.bitTier = 2; seen[GOLD] = 1; ledger.dig = 42; stats.dug = 321;
|
||||
for (let y = 36; y < 40; y++) for (let x = 40; x < 44; x++) setCell(y * W + x, EMPTY, 20, 0);
|
||||
undoRecord('Wall', () => { const err = placeBlock(BP_WALL, RSTONE, 10, 9); if (err) throw new Error(err); });
|
||||
window.claimTest = { id: GAME.worldId, seed: worldSeed, bag: Array.from(bag), career: GAME.careerId };
|
||||
renderNotebook();
|
||||
}""")
|
||||
cp.wait_for_function("$('claim-open') && !$('claim-open').disabled")
|
||||
cp.click('#claim-open'); cp.locator('#dlg-foot').get_by_role('button', name='Cancel', exact=True).click()
|
||||
check('opening a claim asks for confirmation', ev('career.claims.length === 1 && money === 10000'))
|
||||
cp.click('#claim-open'); cp.locator('#dlg-foot').get_by_role('button', name='Open claim', exact=True).click()
|
||||
cp.wait_for_function('career.claims.length === 2 && !claimBusy', timeout=20000)
|
||||
ev('GAME.paused = true')
|
||||
check('new claim carries money, bag, upgrades and knowledge', ev("money === 5000 && earned === 12345 && JSON.stringify(Array.from(bag)) === JSON.stringify(claimTest.bag) && player.bitTier === 2 && seen[GOLD] === 1 && ledger.dig === 42 && stats.dug === 321"))
|
||||
check('claim 2 has doubled debt, a new seed and the same dimensions', ev('debt === 40000 && worldSeed !== claimTest.seed && W === 512 && H === 384'))
|
||||
check('claim 2 is stored with its career and name', ev("async () => { const c = await DB.get('career:' + GAME.careerId); const w = (await listWorlds()).find(w => w.id === GAME.worldId); return c.claims.length === 2 && c.claimNo === 2 && w.name === 'Claim 2' && w.career === c.id && w.claimNo === 2; }"))
|
||||
check('new claim shows its arrival card', ev("$('cards').textContent.includes('New claim') && $('cards').textContent.includes('$40,000')"))
|
||||
ev("openNotebook('Claims')")
|
||||
cp.wait_for_function("$('nb-body').querySelectorAll('[data-travel]').length === 1")
|
||||
check('Claims lists both claims with here, size and paid off', ev("$('nb-body').textContent.includes('Claim 2 · here') && $('nb-body').textContent.includes('512×384') && $('nb-body').textContent.includes('paid off ✓')"))
|
||||
cp.screenshot(path=str(out / '09-claims.png'))
|
||||
cp.click('[data-travel]'); cp.locator('#dlg-foot').get_by_role('button', name='Cancel', exact=True).click()
|
||||
check('travelling asks for confirmation', ev('GAME.worldId !== claimTest.id'))
|
||||
cp.click('[data-travel]'); cp.locator('#dlg-foot').get_by_role('button', name='Travel', exact=True).click()
|
||||
cp.wait_for_function('GAME.worldId === claimTest.id && !claimBusy', timeout=20000)
|
||||
ev('GAME.paused = true')
|
||||
check('travel restores old buildings with shared money and bag', ev('blockP[9 * BW + 10] === BP_WALL && money === 5000 && JSON.stringify(Array.from(bag)) === JSON.stringify(claimTest.bag) && player.bitTier === 2 && debt === 0'))
|
||||
ev("openNotebook('Claims')")
|
||||
cp.wait_for_function("$('claim-open') && !$('claim-open').disabled")
|
||||
check('returning to claim 1 still offers claim 3 at $80,000', ev("$('claim-open').textContent.includes('$80,000')"))
|
||||
cp.screenshot(path=str(out / '09-claims-open.png'))
|
||||
ev('quitToTitle()'); cp.wait_for_function("!$('btn-continue').hidden")
|
||||
cp.click('#btn-continue'); cp.wait_for_function('GAME.running')
|
||||
ev('GAME.paused = true')
|
||||
check('Continue keeps the career state', ev('GAME.worldId === claimTest.id && GAME.careerId === claimTest.career && money === 5000 && player.bitTier === 2 && JSON.stringify(Array.from(bag)) === JSON.stringify(claimTest.bag)'))
|
||||
check('failed claim save keeps the old world and money', ev("""async () => {
|
||||
const op = DB.op; let writes = 0;
|
||||
DB.op = function(mode, fn) { if (mode === 'readwrite' && ++writes === 2) return Promise.reject(new Error('test full')); return op.call(this, mode, fn); };
|
||||
try { return !await openNewClaim() && GAME.worldId === claimTest.id && money === 5000 && debt === 0 && blockP[9 * BW + 10] === BP_WALL && career.claims.length === 2; }
|
||||
finally { DB.op = op; }
|
||||
}"""))
|
||||
check('old world gets a career without changing its money or bag', ev("""async () => {
|
||||
const s = serializeWorld(), id = newWorldId();
|
||||
s.meta.economy.money = 777; s.meta.bag[RSTONE] = 37;
|
||||
await putWorldEntry({ id, name: 'Old world', seed: s.meta.seed, w: W, h: H });
|
||||
await DB.put(id + ':main', { ...s, savedAt: Date.now() });
|
||||
await startFromSave(await worldNewest(id)); GAME.paused = true;
|
||||
const c = await DB.get('career:' + GAME.careerId);
|
||||
return money === 777 && bag[RSTONE] === 37 && c.claimNo === 1 && c.claims[0] === id;
|
||||
}"""))
|
||||
check('broken career data falls back to the world state', ev("""async () => {
|
||||
await saveWorld('main', true); const id = GAME.worldId, cid = GAME.careerId;
|
||||
const c = await DB.get('career:' + cid);
|
||||
for (const bad of [{ ...c, bag: ['bad'] }, { ...c, player: { ...c.player, bitTier: 999 } }, { ...c, stats: [] }, { ...c, money: Infinity }, { ...c, seen: [3] }, { ...c, ledger: null }, undefined]) {
|
||||
if (bad) await DB.put('career:' + cid, bad); else await DB.del('career:' + cid);
|
||||
if (!await startFromSave(await worldNewest(id)) || money !== 777 || bag[RSTONE] !== 37) return false;
|
||||
GAME.paused = true;
|
||||
}
|
||||
return true;
|
||||
}"""))
|
||||
check('deleting claims updates membership and deletes the last career', ev("""async () => {
|
||||
const cid = claimTest.career, c = await DB.get('career:' + cid);
|
||||
await deleteWorld(c.claims[0]);
|
||||
const left = await DB.get('career:' + cid);
|
||||
if (left.claims.length !== 1 || left.claimNo !== 2) return false;
|
||||
await deleteWorld(left.claims[0]);
|
||||
return await DB.get('career:' + cid) === undefined;
|
||||
}"""))
|
||||
cc.close(); ev = pg.evaluate
|
||||
ev(f'GAME.paused = {json.dumps(career_play_paused)}')
|
||||
|
||||
# 9b. selling: goods sell the moment they drop into the dock; orders pay a lump sum and send a truck
|
||||
ev("SET.cardSeconds = 9; orders = []; nextOrderT = 1e12; R.floaters = [];")
|
||||
bot_home = ev('[bot.x, bot.y]')
|
||||
|
||||
Reference in New Issue
Block a user