Vacuum: deselect what is blown out, Ctrl + wheel scrolls the bag, Ctrl+click fix (t20)

Blowing out the last of a selected material removes it from the selection,
so an emptied selection picks up what you click again. Ctrl + wheel never
zooms the page and scrolls the bag list under the mouse. A bag click while
Ctrl is held adds to the selection even if the click lacks the Ctrl flag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 14:16:47 -04:00
co-authored by Claude Opus 5.5
parent cd483dd546
commit 248aba439e
9 changed files with 56 additions and 12 deletions
+16 -2
View File
@@ -333,10 +333,12 @@ with sync_playwright() as p:
ev('GAME.blow.clear(); lastBagKey = ""; hudDirty = true'); settle(80)
pg.locator('#baglist .pick').filter(has_text='Coal').click(); settle(80)
hold(dx_, dy_, 400, 'right'); settle(400)
check('blowing the last coal keeps it selected', ev('bag[COAL] === 0 && GAME.blow.has(COAL)'))
check('blowing the last coal deselects it', ev('bag[COAL] === 0 && !GAME.blow.size'))
check('a selection emptied by blowing picks up what you click again', ev("(() => { GAME.vacFilter = 0; primaryPress(false); const f = GAME.vacFilter; primaryRelease(false); return f !== -2; })()"))
check('a material selected before you have any stays selected', ev("(() => { GAME.blow = new Set([COAL]); const n = bagTotal, f = flyers.length; GAME.rmb = true; secondaryPress(false); toolTick(); GAME.rmb = false; return GAME.blow.has(COAL); })()"))
check('selected but none in bag blows nothing', ev("(() => { const n = bagTotal, f = flyers.length; GAME.rmb = true; secondaryPress(false); toolTick(); GAME.rmb = false; renderSelCard(); return bagTotal === n && flyers.length === f && GAME.status === 'None of the selected materials are in the bag.' && $('selcard').querySelector('.vacchoice').textContent === 'none in bag'; })()"))
check('nothing selected blows nothing and explains how to choose', ev("(() => { GAME.blow.clear(); const n = bagTotal, f = flyers.length; GAME.rmb = true; secondaryPress(false); toolTick(); GAME.rmb = false; return bagTotal === n && flyers.length === f && GAME.status === 'Nothing selected: click or Q/E in the bag.'; })()"))
check('a mix keeps exhausted coal selected and continues blowing ore', ev("(() => { const b = bag.slice(), total = bagTotal, f = flyers.length; bag.fill(0); bag[COAL] = 1; bag[CUORE] = 100; bagTotal = 101; GAME.blow = new Set([COAL, CUORE]); GAME.rmb = true; secondaryPress(false); toolTick(); const ore = bag[CUORE]; toolTick(); GAME.rmb = false; const ok = !bag[COAL] && ore > 0 && bag[CUORE] < ore && GAME.blow.size === 2 && GAME.blow.has(COAL) && GAME.blow.has(CUORE); bag.set(b); bagTotal = total; flyers.length = f; return ok; })()"))
check('a mix drops exhausted coal and continues blowing ore', ev("(() => { const b = bag.slice(), total = bagTotal, f = flyers.length; bag.fill(0); bag[COAL] = 1; bag[CUORE] = 100; bagTotal = 101; GAME.blow = new Set([COAL, CUORE]); GAME.rmb = true; secondaryPress(false); toolTick(); const ore = bag[CUORE]; toolTick(); GAME.rmb = false; const ok = !bag[COAL] && ore > 0 && bag[CUORE] < ore && GAME.blow.size === 1 && GAME.blow.has(CUORE); bag.set(b); bagTotal = total; flyers.length = f; return ok; })()"))
# Shift + right click blows an even mix of everything loose in the bag, without changing the choice
refill('bag[COAL] = 60; bag[CUORE] = 60')
ev('GAME.blow = new Set([COAL]); lastBagKey = ""; hudDirty = true;')
@@ -386,6 +388,11 @@ with sync_playwright() as p:
pg.locator('#baglist .none .pick[title="Select Sand"]').click(modifiers=['Control']); settle(80)
check('Ctrl click selects a material not in the bag and keeps its row after release', ev("GAME.blow.has(SAND) && !GAME.ctrl && !!$('baglist').querySelector('.bagrow.none.on .pick[title=\"Select Sand\"]')"))
check('drag picks the newly selected missing material', ev("(() => { const aim = GAME.aim, x = Math.floor(bot.x)+6, y = Math.floor(bot.y)-6, i = y*W+x, old = [mat[i],temp[i],flags[i]]; setCell(i,SAND,20,0); GAME.aim = {x,y}; GAME.lmb = true; primaryPress(false); toolTick(); primaryRelease(false); GAME.lmb = false; GAME.aim = aim; const ok = bag[SAND] > 0; setCell(i,...old); return ok; })()"))
# Ctrl held (keydown seen) but the click itself arrives without ctrlKey, as on some Linux setups: still adds
ev("GAME.blow = new Set([COAL]); seen[GRAVEL] = 1; bagTotal -= bag[GRAVEL]; bag[GRAVEL] = 0; window.dispatchEvent(new KeyboardEvent('keydown', {key:'Control', ctrlKey:true})); renderBag()")
pg.locator('#baglist .none .pick[title="Select Gravel"]').click(); settle(80)
check('a click while Ctrl is held adds even without ctrlKey on the click', ev('GAME.blow.has(COAL) && GAME.blow.has(GRAVEL)'), ev('[...GAME.blow]'))
ev("GAME.blow.delete(GRAVEL); GAME.blow.add(SAND)")
ev("GAME.blow.delete(SAND); bagTotal -= bag[SAND]; bag[SAND] = 0; window.dispatchEvent(new KeyboardEvent('keyup', {key:'Control'})); renderBag()")
check('Ctrl release hides unselected missing materials', ev("""!GAME.ctrl && !$('baglist').querySelector('.bagrow.none .pick[title="Select Sand"]')"""))
ev("window.dispatchEvent(new KeyboardEvent('keydown', {key:'Meta', metaKey:true})); renderBag()")
@@ -394,6 +401,13 @@ with sync_playwright() as p:
check('Meta release hides unselected missing materials', ev('!GAME.ctrl'))
ev("window.dispatchEvent(new KeyboardEvent('keydown', {key:'Control', ctrlKey:true})); window.dispatchEvent(new Event('blur')); renderBag()")
check('blur clears the modifier', ev('!GAME.ctrl'))
# Ctrl + wheel over the bag scrolls the list instead of zooming the page
r = ev("""(() => { const b = $('baglist'), mh = b.style.maxHeight; b.style.maxHeight = '40px'; b.scrollTop = 0;
const w = new WheelEvent('wheel', { deltaY: 30, ctrlKey: true, bubbles: true, cancelable: true }); b.querySelector('.pick').dispatchEvent(w);
const out = [w.defaultPrevented, b.scrollTop]; b.style.maxHeight = mh; b.scrollTop = 0; return out; })()""")
check('Ctrl + wheel over the bag scrolls it and never zooms the page', r[0] and r[1] > 0, r)
r = ev("(() => { const w = new WheelEvent('wheel', { deltaY: 30, ctrlKey: true, bubbles: true, cancelable: true }); $('selcard').dispatchEvent(w); return w.defaultPrevented; })()")
check('Ctrl + wheel over other HUD panels never zooms the page', r)
pg.locator('[data-bag-clear]').click(); settle(80)
check('Clear clears the selection', ev('!GAME.blow.size'))
pg.locator('#baglist .pick').filter(has_text='Coal').click(); settle(80)