Vacuum: holding Shift shows the blow-everything mix on the card and in the bag (t19)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -395,9 +395,9 @@ The notebook (N): milestones, market, wallet, blueprints, controls.
|
||||
- functions: openNotebook, renderNotebook, fmtClock, orderName, orderLeft, renderMarketTab, fmtPrice, itemsText, renderWallet, renderBlueprintTab, copyCode, controlsHtml
|
||||
- variables: nbTab, MARKET_GROUPS
|
||||
|
||||
### src/ui/hud.js (39 lines)
|
||||
### src/ui/hud.js (40 lines)
|
||||
The tool hotbar and what is selected.
|
||||
- functions: renderHotbar, toolId, steering, modShift, grainAt, selectTool, bagMaterials, blowList, blowAllList, ensureBlow, piece
|
||||
- functions: renderHotbar, toolId, steering, modShift, grainAt, selectTool, bagMaterials, blowList, blowAllList, blowingAll, ensureBlow, piece
|
||||
|
||||
### src/ui/build-menu.js (102 lines)
|
||||
The build menu along the bottom: categories, piece tiles and their icons.
|
||||
|
||||
@@ -4,6 +4,18 @@ What agents have done, newest first. Add an entry for every piece of work: the d
|
||||
note or request it was for, what changed, the files touched, the tests run, and anything left
|
||||
open or not verified. Keep each entry short; the git history has the details.
|
||||
|
||||
## 2026-10-24: t19 Vacuum blow all visual (Claude Code, Codex)
|
||||
|
||||
- The owner's description was lost in kandown; chosen in chat: bag rows light up and the card
|
||||
shows it while Shift is held. t18 was deleted at the owner's request (to decide later: what
|
||||
blow does when the chosen material runs out).
|
||||
- `hud.js` `blowingAll()` (Shift held and not flying, or blowing everything); `selection.js` card
|
||||
("Everything · mix of N", no swatches so it stays one line) and bag `.on` rows; `previews.js`
|
||||
cursor swatches.
|
||||
- `test/play.py`: Shift preview on and off, flying doesn't preview (the bot is put back after,
|
||||
or a later gamepad dig check fails). Tests: `run_all.py --browser` all pass (220 `play.py`
|
||||
checks).
|
||||
|
||||
## 2026-10-24: t16 follow-up: Shift blows all, Ctrl+click in the bag, compact menu (Claude Code)
|
||||
|
||||
- The owner's subtask "shift to blow all" and two chat requests. Codex was out of credits, so
|
||||
|
||||
@@ -31,6 +31,7 @@ function bagMaterials() { return BAG_ORDER.filter(m => bag[m] > 0); }
|
||||
function blowList() { return [...GAME.blow]; }
|
||||
// Shift + right click: an even mix of everything loose in the bag (bars never mix)
|
||||
function blowAllList() { return bagMaterials().filter(m => PH[m] !== PH_ITEM && (PH[m] !== PH_LIQUID || player.flask)); }
|
||||
function blowingAll() { return toolId() === 'vacuum' && (GAME.rmb ? !GAME.rmbConsumed && GAME.blowAll : modShift()); }
|
||||
// Empty materials stay chosen until the player changes the marks.
|
||||
function ensureBlow() {
|
||||
if (GAME.blow.size) return;
|
||||
|
||||
+1
-1
@@ -153,7 +153,7 @@ function drawPreviews() {
|
||||
if (t === 'vacuum') {
|
||||
// what the right button would blow, next to the cursor; what the left is sucking, while it sucks
|
||||
const sz = Math.max(6, zp * 1.6), qx = p.x + (r + 1.2) * zp, qy = p.y - (r + 1.2) * zp;
|
||||
const swatches = GAME.lmb ? GAME.vacFilter >= 0 && GAME.collect.size ? [...GAME.collect] : [] : GAME.rmb && GAME.blowAll ? blowAllList() : blowList();
|
||||
const swatches = GAME.lmb ? GAME.vacFilter >= 0 && GAME.collect.size ? [...GAME.collect] : [] : blowingAll() ? blowAllList() : blowList();
|
||||
swatches.slice(0, 4).forEach((m, k) => { ctx.fillStyle = rgbOf(m); ctx.fillRect(qx + k * (sz + 2), qy, sz, sz); });
|
||||
if (blowing || GAME.lmb) {
|
||||
// faint line from the nozzle: the path the grains take
|
||||
|
||||
+5
-5
@@ -229,11 +229,11 @@ function renderSelCard() {
|
||||
+ '<div class="sub"><kbd>Q</kbd>/<kbd>E</kbd> piece · <kbd>Shift</kbd>+<kbd>Q</kbd>/<kbd>E</kbd> tab · <kbd>R</kbd> turn or material · <kbd>F</kbd> material menu · hold <kbd>G</kbd> replace · right click take back · hold <kbd>C</kbd>/<kbd>X</kbd> copy/cut · <kbd>V</kbd> paste · <kbd>Ctrl</kbd>+<kbd>Z</kbd> undo</div>';
|
||||
} else if (t === 'vacuum') {
|
||||
ensureBlow();
|
||||
const list = blowList(), marks = [...GAME.collect];
|
||||
const all = blowingAll(), list = all ? blowAllList() : blowList(), marks = [...GAME.collect];
|
||||
const sws = ms => ms.slice(0, 4).map(m => `<span class="sw" title="${esc(MD[m].name)}" style="background:${rgbOf(m)}"></span>`).join('') + (ms.length > 4 ? `+${ms.length - 4}` : '');
|
||||
const count = list.reduce((n, m) => n + bag[m], 0);
|
||||
h = `<div class="row vacrow"><b>Pick up</b><button class="chip hot" data-vac-menu>${marks.length ? 'Only marked' : 'Everything'} · F</button>${sws(marks)}</div>
|
||||
<div class="row vacrow"><b>Blow out</b><kbd>Q</kbd><button class="name grow vacchoice" data-vac-menu>${sws(list)}${list.length > 1 ? `Mix of ${list.length}` : list.length ? esc(MD[list[0]].name) : 'bag empty'}</button><span class="num chip${count ? '' : ' bad'}">${count ? count.toLocaleString('en-US') : 'none left'}</span><kbd>E</kbd></div>
|
||||
<div class="row vacrow"><b>Blow out</b><kbd>Q</kbd><button class="name grow vacchoice" data-vac-menu>${all ? '' : sws(list)}${all ? list.length ? `Everything · mix of ${list.length}` : 'Everything · nothing loose' : list.length > 1 ? `Mix of ${list.length}` : list.length ? esc(MD[list[0]].name) : 'bag empty'}</button><span class="num chip${count ? '' : ' bad'}">${count ? count.toLocaleString('en-US') : 'none left'}</span><kbd>E</kbd></div>
|
||||
<div class="sub">Left picks up, right blows out. F chooses what. R marks what is under the cursor. Shift takes or blows everything. <span class="chip">nozzle ${GAME.brush[1]}</span></div>`;
|
||||
} else if (t === 'ignite') {
|
||||
h = `<div class="row"><span class="name">Igniter</span><span class="chip hot">up to 640°C</span></div><div class="sub">Hold on fuel to light it. Coal catches around 420°C, wood around 300°C. Fuel needs open air next to it.</div>`;
|
||||
@@ -248,14 +248,14 @@ function renderBag() {
|
||||
$('bagbar').firstChild.style.width = pct + '%';
|
||||
$('bagbar').classList.toggle('full', bagTotal >= cap);
|
||||
const l = BAG_ORDER.filter(m => bag[m] > 0 || GAME.collect.has(m) || GAME.blow.has(m));
|
||||
const t = toolId();
|
||||
const key = l.map(m => m + ':' + bag[m] + (GAME.collect.has(m) ? 'c' : '') + (GAME.blow.has(m) ? 'b' : '')).join(',') + '|' + GAME.wallMat + '|' + GAME.filterCfg.m.join('.') + '|' + t + '|' + GAME.pieceIdx;
|
||||
const t = toolId(), all = blowingAll(), blowing = all ? blowAllList() : blowList();
|
||||
const key = l.map(m => m + ':' + bag[m] + (GAME.collect.has(m) ? 'c' : '') + (GAME.blow.has(m) ? 'b' : '')).join(',') + '|' + GAME.wallMat + '|' + GAME.filterCfg.m.join('.') + '|' + t + '|' + GAME.pieceIdx + '|' + all;
|
||||
if (key === lastBagKey) return;
|
||||
lastBagKey = key;
|
||||
const box = $('baglist'); box.innerHTML = '';
|
||||
if (!l.length) { box.appendChild(el('div', { class: 'empty' }, 'Empty. Break rock with the Drill, then use the Vacuum.')); return; }
|
||||
for (const m of l) {
|
||||
const sel = (t === 'vacuum' && GAME.blow.has(m)) || (t === 'build' && m === GAME.wallMat && pieceUsesWall(piece())) || (t === 'build' && piece().filter && GAME.filterCfg.m.includes(m));
|
||||
const sel = (t === 'vacuum' && blowing.includes(m)) || (t === 'build' && m === GAME.wallMat && pieceUsesWall(piece())) || (t === 'build' && piece().filter && GAME.filterCfg.m.includes(m));
|
||||
const row = el('div', { class: 'bagrow' + (sel ? ' on' : '') });
|
||||
if (t === 'vacuum' && GAME.collect.has(m)) row.appendChild(el('span', { class: 'tag', title: 'Marked to pick up', 'aria-label': 'Marked to pick up' }, '⬇'));
|
||||
const b = el('button', { class: 'pick', title: WALL_OF[m] && t === 'build' ? `Build with ${MD[m].name}` : `Blow out ${MD[m].name}` });
|
||||
|
||||
@@ -330,6 +330,18 @@ with sync_playwright() as p:
|
||||
# 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.collect = new Set([COAL, CUORE]); GAME.blow = new Set([COAL]); lastBagKey = ""; hudDirty = true;')
|
||||
pg.keyboard.down('Shift'); settle(150)
|
||||
check('Shift previews everything in the blow card', 'Everything · mix of' in pg.inner_text('#selcard'))
|
||||
check('Shift lights every loose bag row', ev("blowAllList().every(m => [...$('baglist').querySelectorAll('.bagrow.on .nm')].some(e => e.textContent === MD[m].name))"))
|
||||
pg.screenshot(path=str(out / '03b-blow-all-preview.png'))
|
||||
pg.keyboard.up('Shift'); settle(150)
|
||||
check('releasing Shift restores the chosen blow material', ev("$('selcard').querySelector('.vacchoice').textContent.includes(MD[COAL].name) && !$('selcard').querySelector('.vacchoice').textContent.includes('Everything')"))
|
||||
check('releasing Shift lights only coal', ev("(() => { const rows = [...$('baglist').querySelectorAll('.bagrow.on')]; return rows.length === 1 && rows[0].querySelector('.nm').textContent === MD[COAL].name; })()"))
|
||||
bot_at = ev('[bot.x, bot.y]')
|
||||
pg.keyboard.down('d'); pg.keyboard.down('Shift'); settle(150)
|
||||
check('Shift while flying does not preview everything', 'Everything' not in pg.locator('#selcard .vacchoice').inner_text())
|
||||
pg.keyboard.up('Shift'); pg.keyboard.up('d')
|
||||
ev(f'bot.x = {bot_at[0]}; bot.y = {bot_at[1]}; bot.vx = bot.vy = 0;'); settle(150)
|
||||
mx_, my_ = cell_to_screen(bx - 26, gy - 6)
|
||||
pg.mouse.move(mx_, my_); pg.keyboard.down('Shift'); pg.mouse.down(button='right'); settle(400); pg.mouse.up(button='right'); pg.keyboard.up('Shift'); settle(600)
|
||||
check('Shift + right click blows everything loose in the bag', ev('bag[CUORE]') < 60 and ev('bag[COAL]') < 60 and ev('GAME.blow.size === 1 && GAME.blow.has(COAL)'), ev('[bag[COAL], bag[CUORE]]'))
|
||||
|
||||
Reference in New Issue
Block a user