Vacuum: pick up what you click, blow out what's in hand (t20)

A drag takes only the material it starts on (Shift: everything). The blow
selection is the hand: click or Q/E for one material, Ctrl+click for a mix.
Empty materials leave the hand, an empty hand blows nothing, and a pickup
fills an empty hand. Removes the pick-up marks and the F vacuum menu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 13:34:44 -04:00
co-authored by Claude Opus 5.5
parent 14194cb4be
commit c1a085ebb1
17 changed files with 129 additions and 186 deletions
+10 -6
View File
@@ -44,7 +44,6 @@ function doInteract() {
if (msg) break outer;
}
if (msg) { setStatus(msg, 'info'); if (!/^New (drill bit|bag)/.test(msg)) toast(msg); }
else if (toolId() === 'vacuum') openVacuumMenu();
else if ((moldAt(ax, ay) || {}).kind !== 'ingot') setStatus('Nothing to use there.', 'info'); // an ingot mold needs no F: say nothing
}
// Pick (middle mouse): the piece under the cursor becomes the one you build, with its
@@ -119,7 +118,7 @@ function primaryPress(shift) {
return;
}
if (t === 'vacuum') {
GAME.vacFilter = shift || !GAME.collect.size ? -1 : 0;
GAME.vacFilter = shift ? -1 : grainAt(ax, ay);
hudDirty = true;
} else if (t === 'build') {
const P = piece();
@@ -205,9 +204,13 @@ function toolTick() {
const r = toolPulse(ax, ay, GAME.drillW, GAME.drillTune);
if (r.fired) { playSfx('pulse', GAME.drillW); if (r.status) setStatus(r.status); }
} else if (t === 'vacuum') {
const r = toolVacuum(ax, ay, GAME.brush[1], GAME.vacFilter < 0 || !GAME.collect.size ? () => true : m => GAME.collect.has(m));
if (r.got) { playSfx('suck'); hudDirty = true; }
if (r.status) setStatus(r.status);
if (GAME.vacFilter === 0) { GAME.vacFilter = grainAt(ax, ay); if (GAME.vacFilter) hudDirty = true; }
const f = GAME.vacFilter;
if (f !== 0) {
const r = toolVacuum(ax, ay, GAME.brush[1], f < 0 ? () => true : m => m === f);
if (r.got) { if (!GAME.blow.size) { GAME.blow = new Set([f > 0 ? f : r.m]); lastBagKey = ''; } playSfx('suck'); hudDirty = true; }
if (r.status) setStatus(r.status);
}
} else if (t === 'ignite') {
if (inReach(ax, ay)) { const r = toolIgnite(ax, ay); playSfx('spark'); if (Math.random() < 0.6) spawnSpark(ax + 0.5, ay + 0.5); if (!r.fuel) setStatus('Aim at coal or wood touching air to light it.'); }
else setStatus('Out of reach.');
@@ -215,9 +218,10 @@ function toolTick() {
}
if (GAME.rmb && !GAME.rmbConsumed) {
if (t === 'vacuum') {
ensureBlow();
if (!GAME.blowAll && !GAME.blow.size) { setStatus('Nothing in hand: Q/E or click something in the bag.'); return; }
const list = GAME.blowAll ? blowAllList() : blowList();
const r = GAME.blowAll && !list.length ? { placed: 0, status: 'Nothing loose in the bag to blow.' } : toolBlow(ax, ay, GAME.brush[1], list[0] || 0, list.length > 1 ? list : null);
for (const m of GAME.blow) if (bag[m] <= 0) { GAME.blow.delete(m); lastBagKey = ''; hudDirty = true; }
if (r.placed) { playSfx('blow'); hudDirty = true; } else if (r.status) setStatus(r.status);
} else if (t === 'build') {
const key = `${(ax / BS) | 0},${(ay / BS) | 0}`;