Silo contents at a glance (t38); drill aimed past its reach stays calm (t41)
Silos show a wide fill window in the material's colour in both looks, and the cursor label names the contents anywhere over the outline. Aiming the drill beyond its reach keeps normal colours, marks where the pulse stops, and drops the red circle and the out-of-reach toast. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1134,6 +1134,7 @@ with sync_playwright() as p:
|
||||
settle(1500)
|
||||
ev("__pad.buttons[7].pressed = false; __pad.buttons[7].value = 0;")
|
||||
settle(200)
|
||||
check('gamepad drill aim stays within its reach', ev('Math.hypot(GAME.padAim.x, GAME.padAim.y) <= drillReach(GAME.drillW)'))
|
||||
check('gamepad RT digs where the right stick aims', ev('stats.dug') > d0, f"{d0}->{ev('stats.dug')}")
|
||||
ev("__pad.buttons[5].pressed = true;"); settle(100); ev("__pad.buttons[5].pressed = false;"); settle(100)
|
||||
check('gamepad RB switches to the vacuum', ev('GAME.tool') == 1)
|
||||
@@ -1185,6 +1186,77 @@ with sync_playwright() as p:
|
||||
fp.goto(url)
|
||||
fp.evaluate('startNewWorld(4242, 512, 384)')
|
||||
fp.wait_for_function('GAME.running')
|
||||
# Silo feedback uses real pointer positions; drawing checks sample an isolated canvas.
|
||||
fp.evaluate("""() => {
|
||||
GAME.paused = true; SET.fog = false; SET.look = 'pixel'; SET.zoom = 8; SET.cursorLabel = true;
|
||||
SET.cameraLead = false; SET.cameraSmooth = 0; resizeRender();
|
||||
for (let y = 80; y < 140; y++) for (let x = 80; x < 160; x++) { setCell(y * W + x, EMPTY, 20, 0); bgm[y * W + x] = 0; }
|
||||
window.testSilo = addMachine('silo', 28, 25, 0);
|
||||
bot.x = 104; bot.y = 106; snapCamera(); $('cards').replaceChildren();
|
||||
}""")
|
||||
for amount in [0, 2000]:
|
||||
fp.evaluate(f'testSilo.sm = SAND; testSilo.sn = {amount}')
|
||||
for name, dx, dy in [('drum', 5, 8), ('hatch with snow', 5, 0), ('cone gap', 1, 22), ('leg', 0, 23), ('gate', 5, 23)]:
|
||||
fp.evaluate('setCell((testSilo.y) * W + testSilo.x + 5, SNOW, -10, 0)')
|
||||
point = fp.evaluate(f'(() => {{ const p = worldToScreenPx(testSilo.x + {dx} + 0.5, testSilo.y + {dy} + 0.5); return [p.x * innerWidth / R.canvas.width, p.y * innerWidth / R.canvas.width]; }})()')
|
||||
fp.mouse.move(*point); fp.wait_for_timeout(200)
|
||||
want = 'sand 2,000 / 4,000' if amount else 'empty'
|
||||
check(f'silo {name} hover shows {want}', fp.evaluate(f"hoverInfo(Math.floor(GAME.aim.x), Math.floor(GAME.aim.y)).t1 === 'Silo' && hoverInfo(Math.floor(GAME.aim.x), Math.floor(GAME.aim.y)).contents === '{want}' && $('info').textContent.includes('{('holds 2,000 / 4,000 sand' if amount else 'empty')}')"))
|
||||
check(f'silo {name} cursor label draws {want} in normal colour', fp.evaluate("""() => {
|
||||
const calls = [], ctx = R.ctx, text = ctx.fillText;
|
||||
ctx.fillText = function(t) { calls.push([t, this.fillStyle]); };
|
||||
try { drawCursorLabel(500, 300, 1); } finally { ctx.fillText = text; }
|
||||
const info = hoverInfo(Math.floor(GAME.aim.x), Math.floor(GAME.aim.y));
|
||||
return calls.some(([t, c]) => t === info.contents && c === '#efe6d8');
|
||||
}"""))
|
||||
check('snow in silo is named snow', fp.evaluate("testSilo.sm = SNOW; hoverInfo(testSilo.x + 5, testSilo.y + 8).contents === 'snow 2,000 / 4,000'"))
|
||||
for look in ['pixel', 'smooth']:
|
||||
check(f'{look} silo fill pixels show empty, near empty, half and full at zooms 2 through 12', fp.evaluate("""pixel => {
|
||||
const canvas = document.createElement('canvas'); canvas.width = 160; canvas.height = 300;
|
||||
const ctx = canvas.getContext('2d'), mm = { x: 112, y: 100, sm: SAND };
|
||||
const at = (x, y, z) => Array.from(ctx.getImageData(Math.floor(x * z), Math.floor(y * z), 1, 1).data).slice(0, 3).join(',');
|
||||
for (let z = 2; z <= 12; z++) for (const [n, h] of [[0, 0], [1, 1], [2000, 8], [4000, 16]]) {
|
||||
mm.sn = n; drawSiloWindow(ctx, mm, 0, 0, z, pixel);
|
||||
for (let y = 3; y < 19; y++) if ((at(9.5, y + 0.5, z) !== '20,24,28') !== (y >= 19 - h)) return false;
|
||||
}
|
||||
// Every powder siloTick accepts must stand apart from dark glass, including coal.
|
||||
for (let m = 1; m < NMAT; m++) if (PH[m] === PH_POWDER) {
|
||||
mm.sm = m; mm.sn = 2000; drawSiloWindow(ctx, mm, 0, 0, 2, pixel);
|
||||
const filled = at(9.5, 18.5, 2).split(',').map(Number);
|
||||
if (Math.max(...filled.map((c, k) => Math.abs(c - [20, 24, 28][k]))) < 25) return false;
|
||||
const image = ctx.getImageData(0, 0, 24, 48).data.slice().join(',');
|
||||
drawSiloWindow(ctx, mm, 0, 0, 2, pixel);
|
||||
if (ctx.getImageData(0, 0, 24, 48).data.join(',') !== image) return false;
|
||||
}
|
||||
return true;
|
||||
}""", look == 'pixel'))
|
||||
fp.set_viewport_size({'width': 700, 'height': 800})
|
||||
check('silo contents remain available when the narrow HUD hides the info plate', fp.evaluate("getComputedStyle($('info')).display === 'none' && hoverInfo(testSilo.x + 5, testSilo.y + 8).contents === 'snow 2,000 / 4,000'"))
|
||||
fp.set_viewport_size({'width': 1280, 'height': 800})
|
||||
check('other tools still warn beyond reach', fp.evaluate("GAME.tool = 1; hoverInfo(testSilo.x + 80, testSilo.y).warn === 'out of reach'"))
|
||||
# Holding the drill with a distant pointer is ordinary aim, but hard rock still warns.
|
||||
fp.evaluate('bot.y = 130; snapCamera()')
|
||||
fp.keyboard.press('1')
|
||||
fp.mouse.move(1000, 400); fp.wait_for_timeout(100)
|
||||
fp.evaluate("$('toasts').replaceChildren(); lastPulseTick = -99; player.bitTier = 0; GAME.drillTune = 0")
|
||||
fp.evaluate('GAME.paused = false')
|
||||
fp.mouse.down()
|
||||
fp.evaluate('GAME.paused = true; for (let k = 0; k < 24; k++) { tick++; toolTick(); }')
|
||||
check('held drill beyond reach makes no toast or distance label', fp.evaluate("GAME.lmb && !inDrillReach(GAME.aim.x, GAME.aim.y, GAME.drillW) && !$('toasts').children.length && !hoverInfo(Math.floor(GAME.aim.x), Math.floor(GAME.aim.y)).warn && !hoverInfo(Math.floor(GAME.aim.x), Math.floor(GAME.aim.y)).t2.includes('out of reach')"))
|
||||
check('distant drill fan and crosshair stay normal with no red reach circle', fp.evaluate("""() => {
|
||||
const ctx = R.ctx, stroke = ctx.stroke, circle = drawReachCircle, colours = []; let circles = 0;
|
||||
ctx.stroke = function() { colours.push(this.strokeStyle); };
|
||||
drawReachCircle = () => circles++;
|
||||
try { drawPreviews(); } finally { ctx.stroke = stroke; drawReachCircle = circle; }
|
||||
return circles === 0 && !colours.some(c => c.includes('239, 106, 85'));
|
||||
}"""))
|
||||
fp.evaluate("""() => {
|
||||
const o = drillOrigin(), dx = GAME.aim.x + 0.5 - o.x, dy = GAME.aim.y + 0.5 - o.y, d = Math.hypot(dx, dy);
|
||||
for (let k = 6; k < 10; k++) setCell(Math.floor(o.y + dy / d * k) * W + Math.floor(o.x + dx / d * k), GRANITE, 20, F_NAT);
|
||||
tick += 20; toolTick();
|
||||
}""")
|
||||
check('held drill still toasts too hard with a distant pointer', fp.evaluate("$('toasts').textContent.includes('Granite is too hard; needs an iron bit.')"))
|
||||
fp.mouse.up()
|
||||
fp.evaluate("""() => {
|
||||
GAME.paused = true; SET.fog = true; SET.look = 'pixel'; SET.zoom = 6; SET.lighting = 'off';
|
||||
SET.cameraLead = false; SET.cameraSmooth = 0; resizeRender();
|
||||
|
||||
Reference in New Issue
Block a user