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
+2 -2
View File
@@ -22,12 +22,12 @@ const STARTER_DESIGNS = [
// ---------- Milestones ----------
const MILESTONES = [
{ id: 'dig', title: 'Break ground', msg: 'Broken material falls loose. The Vacuum (2) picks up everything, or only what you mark in its menu (F).', hint: 'Hold the left mouse button with the Drill (1): it sends pulses at the cursor that shake rock until it shatters. It falls as rubble, ore and coal.' },
{ id: 'dig', title: 'Break ground', msg: 'Broken material falls loose. The Vacuum (2) picks up what you click. Click or Q/E in the bag chooses the hand; Ctrl+click mixes, Shift takes or blows everything.', hint: 'Hold the left mouse button with the Drill (1): it sends pulses at the cursor that shake rock until it shatters. It falls as rubble, ore and coal.' },
{ id: 'fire', title: 'First fire', hint: 'Vacuum up coal or wood chunks, blow a pile out with right click, then hold the Igniter (4) on it. Fuel only burns where it touches open air.', reward: 'Thermal lens unlocked. Press H to see heat.' },
{ id: 'brick', title: 'Fired brick', hint: 'Clay turns into brick after a while above about 900°C, hotter than an open wood fire gets. Blow clay lumps into a coal fire, best walled in like a furnace, and vacuum up the brick rubble. Brick rubble builds brick blocks.', reward: 'Brick insulates far better than stone and survives 1750°C.' },
{ id: 'charcoal', title: 'Charcoal', hint: 'Wood that gets hot without air turns into charcoal instead of burning. Bury a burning pile of wood chunks under dirt, or heat a sealed box of wood chunks from outside.', reward: 'A fuel you can grow: nearly as hot as coal.' },
{ id: 'grow', title: 'Plant a tree', msg: 'Wood is renewable. Plant rows of acorns on dirt to farm it.', hint: 'Cutting down a tree drops acorns. Leave one on dirt or grass under open sky and it sprouts, then grows into a tree in about a minute and a half.' },
{ id: 'copper', title: 'Molten copper', msg: 'Molten copper sinks to the bottom of the charge. Get it into a mold before it sets.', hint: 'Copper ore melts at 1085°C. An open fire loses too much heat, so wall coal and ore in with blocks and leave a small vent at the top for smoke. Mix ore and coal about half and half: in the vacuum menu (F), mark coal and copper ore with ⬆. Right click blows an even mix.' },
{ id: 'copper', title: 'Molten copper', msg: 'Molten copper sinks to the bottom of the charge. Get it into a mold before it sets.', hint: 'Copper ore melts at 1085°C. An open fire loses too much heat, so wall coal and ore in with blocks and leave a small vent at the top for smoke. Mix ore and coal about half and half: Ctrl+click coal and copper ore in the bag to blow a mix. Right click blows an even mix.' },
{ id: 'bars', title: 'Copper bars', msg: 'Bars sell for far more than the ore in them, and make metal wall blocks.', hint: 'Build an Ingot mold (Build, 3) right under the furnace with a floor of clay Grates between them: molten copper drips through, while the charge and the thick slag stay up. When the bars set, they drop out of the bottom of the mold onto whatever is under it; a belt carries them off. Leave space below, or vacuum up the bars. Ingot molds empty themselves: bars, junk and scrap drop below, slag is thrown away and the grate above is raked. Removing any mold returns its set metal to your bag: whole bars as bars, the rest as scrap. Copper that sets in the furnace melts again next firing.' },
{ id: 'bit1', title: 'Copper drill bit', hint: 'Cast copper in a Bit mold. Building the furnace right on top works. A Grate over the funnel keeps the charge out. Let it set, then press F.', reward: 'Copper bit. You can now dig iron ore.' },
{ id: 'auto', title: 'Moving parts', msg: 'Machines can now haul for you. Feed furnaces automatically, and lift ore out of your mines.', hint: 'Belts carry grains and bars resting on them. Screw tubes push loose material along (never liquids); stacked pointing up they lift it out of a mine. A Filter lets one material fall through and carries the rest along, so you can sort ore from rubble. Move 300 grains with machines.' },
+6 -5
View File
@@ -11,11 +11,11 @@ function vacuumTargetAt(cx, cy, r) {
}
// Vacuum: picks up loose grains, liquids (with the Flask) and bars for which pick(m) is true.
function toolVacuum(cx, cy, r, pick) {
let got = 0, full = false, budget = 48;
let got = 0, first = 0, full = false, budget = 48;
for (const e of entsInCircle(cx, cy, r)) {
if (!pick(e.m) || !inReach(e.ix + 2, e.iy + 1)) continue;
if (bagTotal >= bagCap()) { full = true; break; }
bagAdd(e.m, 1); removeEnt(e); got++;
bagAdd(e.m, 1); removeEnt(e); got++; if (!first) first = e.m;
emit({ t: 'suck', x: e.ix + 2, y: e.iy + 1, m: e.m });
}
if (!full) forBrush(cx, cy, r, (x, y, i) => {
@@ -24,11 +24,12 @@ function toolVacuum(cx, cy, r, pick) {
if (!pick(m)) return;
if (part[i] >= P_TU && part[i] <= P_TR) return;
if (bagTotal >= bagCap()) { full = true; return false; }
if (!first) first = m;
bagAdd(m, 1); setCell(i, EMPTY, AMB[y], 0); got++;
if (got & 1) emit({ t: 'suck', x, y, m });
if (--budget <= 0) return false;
});
return { got, full, status: full ? 'Bag full; blow material out or cast a bigger tank.' : '' };
return { got, m: first, full, status: full ? 'Bag full; blow material out or cast a bigger tank.' : '' };
}
// Blow: grains leave the bot's nozzle and fly to the cursor, where they drop.
// Liquids need the Flask. Bars are thrown, one at a time.
@@ -45,11 +46,11 @@ function toolBlow(cx, cy, r, m, mix) {
let pickM = null;
if (mix && mix.length) {
const avail = mix.filter(k => bag[k] > 0 && PH[k] !== PH_ITEM && (PH[k] !== PH_LIQUID || player.flask));
if (!avail.length) return { placed: 0, status: 'No marked materials left to blow.' };
if (!avail.length) return { placed: 0, status: 'Nothing in hand: Q/E or click something in the bag.' };
pickM = () => { for (let k = 0; k < avail.length; k++) { const c = avail[(blowRR++) % avail.length]; if (bag[c] > 0) return c; } return 0; };
m = avail[0];
}
if (!m) return { placed: 0, status: 'Pick what to blow out: Q/E, or click it in your bag.' };
if (!m) return { placed: 0, status: 'Nothing in hand: Q/E or click something in the bag.' };
if (bag[m] <= 0) return { placed: 0, status: `No ${MD[m].name.toLowerCase()} left.` };
const ph = PH[m];
if (ph === PH_LIQUID && !player.flask) return { placed: 0, status: 'You need the Flask to carry liquids.' };