// Ore identification, cached connected veins, ping timing, settings and label lifetime. const fs = require('fs'); const path = require('path'); const { load, suite, flatWorld } = require('./harness'); const { run } = load(); const { check, done } = suite(); run(`const localStorage = { getItem: () => '{}', setItem() {} };`); for (const f of ['ui/state.js', 'ui/hud.js', 'ui/cursor.js', 'ui/info.js', 'render/overlays.js']) run(fs.readFileSync(path.join(__dirname, '../src', f), 'utf8')); flatWorld(run, 160, 160, 150); for (const m of ['CUV', 'CUORE', 'COALV', 'COAL', 'FEV', 'FEORE', 'COPPER']) check(m + ' is ore-like', run(`oreLike(${m}, null)`)); check('sand and stone are not ore-like', run('!oreLike(SAND, null) && !oreLike(STONE, null)')); check('any hovered bar is ore-like', run('oreLike(EMPTY, { m: BARGL })')); check('default labels are ores only', run("SET.cursorLabel === 'ores'")); for (const [saved, expected] of [[true, 'ores'], [false, 'off'], ['all', 'all']]) { run(`localStorage.getItem = () => '${JSON.stringify({cursorLabel: saved, sv: 2})}'; loadSettings();`); check('saved ' + saved + ' becomes ' + expected, run(`SET.cursorLabel === '${expected}'`)); } check('bit text names the first tier that can drill it', run("BIT_TIERS.every(b => { const m = Array.from(HARD).findIndex(h => h === b.hard); return m < 0 || bitNeeded(m) === 'needs ' + b.name.toLowerCase(); })")); check('undrillable material keeps its warning', run("bitNeeded(Array.from(HARD).findIndex(h => h > 6)) === 'cannot be drilled'")); run(` SET.fog = false; GAME.tool = 0; setCell(20 * W + 20, CUV, 22, F_NAT); setCell(20 * W + 21, CUV, 22, F_NAT); setCell(21 * W + 21, CUV, 22, F_NAT); setCell(21 * W + 20, FEV, 22, F_NAT); setCell(20 * W + 22, CUV, 22, 0); setCell(22 * W + 22, CUV, 22, F_NAT); const v = hoveredVein(20, 20); `); check('fill follows four neighbours of the same natural material', run('v.cells.size === 3 && v.edges.length === 8')); check('moving within the same vein reuses cells and edges', run('hoveredVein(21, 21) === v')); check('leaving the vein removes the outline', run('hoveredVein(22, 20) === null')); check('a disconnected vein gets a new cache', run('hoveredVein(22, 22) !== v')); run(`for (let y = 30; y < 130; y++) for (let x = 0; x < 100; x++) setCell(y * W + x, CUV, 22, F_NAT);`); check('a large vein stops at 6000 cells', run('cursorVein(30 * W).cells.size === 6000')); run(`setCell(W - 1, CUV, 22, F_NAT); setCell(W, CUV, 22, F_NAT);`); check('fill does not wrap across world edges', run('cursorVein(W - 1).cells.size === 1')); run(`setCell(20 * W + 20, FEV, 22, F_NAT);`); check('hover details and warning name the needed bit', run("hoverInfo(20, 20).t2.includes(bitNeeded(FEV)) && hoverInfo(20, 20).warn === bitNeeded(FEV)")); run(` SET.fog = true; fog.fill(0); const realNow = performance.now.bind(performance); let hoverNow = 1000; performance.now = () => hoverNow; GAME.ping = { x: 4, y: 20, t0: 1000, cells: [20 * W + 20] }; `); check('fog hides a vein before the ping reaches it', run("hoverInfo(20, 20).t1 === 'Unexplored' && !hoveredVein(20, 20)")); run('hoverNow = 1100;'); check('a ping names a hidden vein at arrival', run("hoverInfo(20, 20).t1 === MD[FEV].name && hoverInfo(20, 20).t2.includes('found by the ping') && !!hoveredVein(20, 20)")); run('const pingSet = GAME.ping.cellSet; hoverNow = 3099;'); check('ping cells are cached through the fade', run('pingVisible(20, 20) && GAME.ping.cellSet === pingSet && !pingVisible(21, 20)')); run('hoverNow = 3100;'); check('fog hides the vein again at the end of the fade', run("hoverInfo(20, 20).t1 === 'Unexplored' && !hoveredVein(20, 20)")); run('performance.now = realNow;'); check('the name stays fully visible for two seconds', run("cursorLabelAlpha('copper', 100) === 1 && cursorLabelAlpha('copper', 2100) === 1")); check('the name fades over 400 ms', run("cursorLabelAlpha('copper', 2300) === 0.5 && cursorLabelAlpha('copper', 2500) === 0")); check('a different thing brings the label back', run("cursorLabelAlpha('iron', 2600) === 1")); done();