Vacuum menu on F replaces the pick-up modes (t16)
Pick-up takes everything unless something is marked; F with the Vacuum (when nothing in reach can be used) or the card chips open a menu with pick-up and blow toggles per material. The bag rows lose their buttons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+6
-12
@@ -44,6 +44,7 @@ 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
|
||||
@@ -118,10 +119,7 @@ function primaryPress(shift) {
|
||||
return;
|
||||
}
|
||||
if (t === 'vacuum') {
|
||||
const g = GAME.pickMode === 'first' ? grainAt(ax, ay) : 0;
|
||||
GAME.vacFilter = shift || GAME.pickMode === 'all' ? -1 : g;
|
||||
GAME.vacLocked = shift || GAME.pickMode !== 'first' || !!g;
|
||||
if (!shift && GAME.pickMode === 'marked' && !GAME.collect.size) setStatus('Nothing marked to pick up. R over something, or ⬇ in the bag.', 'info');
|
||||
GAME.vacFilter = shift || !GAME.collect.size ? -1 : 0;
|
||||
hudDirty = true;
|
||||
} else if (t === 'build') {
|
||||
const P = piece();
|
||||
@@ -188,7 +186,7 @@ function primaryRelease(shift) {
|
||||
if (r.n || ghosts) { playSfx('place'); setStatus(gtxt || (r.status ? r.status + hint : ''), 'info'); } else { setStatus((r.status || 'Nothing placed.') + hint); playSfx('error'); }
|
||||
GAME.drag = null; GAME.dragDir = -1; hudDirty = true;
|
||||
}
|
||||
if (t === 'vacuum') { GAME.vacFilter = 0; GAME.vacLocked = false; hudDirty = true; }
|
||||
if (t === 'vacuum') { GAME.vacFilter = 0; hudDirty = true; }
|
||||
}
|
||||
function secondaryPress() {
|
||||
const t = toolId();
|
||||
@@ -207,13 +205,9 @@ 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') {
|
||||
if (!GAME.vacLocked && GAME.pickMode === 'first') { const g = grainAt(ax, ay); if (g) { GAME.vacFilter = g; GAME.vacLocked = true; hudDirty = true; } }
|
||||
const f = GAME.vacFilter, marked = GAME.pickMode === 'marked', list = GAME.collect;
|
||||
if (f || marked && list.size) {
|
||||
const r = toolVacuum(ax, ay, GAME.brush[1], f < 0 ? () => true : marked ? m => list.has(m) : m => m === f);
|
||||
if (r.got) { playSfx('suck'); hudDirty = true; }
|
||||
if (r.status) setStatus(r.status);
|
||||
}
|
||||
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);
|
||||
} 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.');
|
||||
|
||||
@@ -86,7 +86,7 @@ function renderBuildBar() {
|
||||
pop.style.left = `${Math.max(8, Math.min(innerWidth - w - 8, r.left + r.width / 2 - w / 2)) - br.left}px`;
|
||||
}
|
||||
function setupBuildBar() {
|
||||
$('selcard').addEventListener('click', e => { if (e.target.closest('[data-wall-picker]')) openWallPicker(); else if (e.target.closest('[data-pick-mode]')) cyclePickMode(); });
|
||||
$('selcard').addEventListener('click', e => { if (e.target.closest('[data-wall-picker]')) openWallPicker(); else if (e.target.closest('[data-vac-menu]')) openVacuumMenu(); });
|
||||
const bar = $('buildbar'); if (!bar) return;
|
||||
bar.addEventListener('click', e => {
|
||||
const t = e.target.closest('[data-cat],[data-piece]'); if (!t) return;
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ function pollPad() {
|
||||
if (padPressed(gp, 0)) doInteract();
|
||||
if (padPressed(gp, 2)) rotate();
|
||||
if (padPressed(gp, 3)) toggleLens();
|
||||
if (padPressed(gp, 1)) { if (GAME.drag) GAME.drag = null; else if (GAME.paste) { GAME.paste = false; hudDirty = true; } else if (toolId() === 'vacuum') cyclePickMode(); }
|
||||
if (padPressed(gp, 1)) { if (GAME.drag) GAME.drag = null; else if (GAME.paste) { GAME.paste = false; hudDirty = true; } }
|
||||
if (padPressed(gp, 10)) bot.lamp = !bot.lamp;
|
||||
if (padPressed(gp, 11)) { SET.zoom = SET.zoom >= 10 ? 2 : SET.zoom + 2; saveSettings(); resizeRender(); R.snapNext = true; }
|
||||
if (padPressed(gp, 8)) openNotebook();
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ window.addEventListener('keydown', e => {
|
||||
case 'q': if (e.shiftKey && toolId() === 'build') cycleBuildCat(-1); else cycleItem(-1); break;
|
||||
case 'e': if (e.shiftKey && toolId() === 'build') cycleBuildCat(1); else cycleItem(1); break;
|
||||
case 'r': rotate(); break;
|
||||
case 't': if (toolId() === 'vacuum') cyclePickMode(); else if (toolId() === 'build' && piece().filter) pickFilterUnderCursor(); break;
|
||||
case 't': if (toolId() === 'build' && piece().filter) pickFilterUnderCursor(); break;
|
||||
case 'f': doInteract(); break;
|
||||
case 'g': GAME.replace = true; hudDirty = true; break;
|
||||
case 'h': toggleLens(); break;
|
||||
|
||||
+5
-5
@@ -170,18 +170,18 @@ function controlsHtml() {
|
||||
const kb = [
|
||||
['Fly', 'W A S D'], ['Boost while flying', 'Shift'], ['Tool modifier (while not flying)', 'Shift'], ['Use tool', 'Left mouse'], ['Second action', 'Right mouse'],
|
||||
['Tools', '1 – 4'], ['Cycle what you blow · piece', 'Q / E'], ['Switch build tab', 'Shift + Q / E'], ['Variant: material · direction · flip', 'R'], ['Wall or mold material menu (Build)', 'F'],
|
||||
['Mark/unmark what is under the cursor (Vacuum)', 'R'], ['Pick-up mode (Vacuum)', 'T'], ['Nozzle or brush size', '[ ] or Shift + wheel'],
|
||||
['Mark/unmark what is under the cursor (Vacuum)', 'R'], ['Vacuum menu: what to pick up and blow', 'F (with the Vacuum, away from anything to use)'], ['Nozzle or brush size', '[ ] or Shift + wheel'],
|
||||
['Replace what is built (Build)', 'Hold G'], ['Copy a box of what you built', 'Hold C, drag'], ['Cut a box (refunded, paste it back)', 'Hold X, drag'], ['Paste again', 'V'], ['Undo building', 'Ctrl + Z'], ['Blueprint library', 'B'], ['Zoom', 'Mouse wheel'], ['Interact (gates, molds, fans, filters)', 'F'], ['Thermal lens', 'H'], ['Info overlay: filters, belt and tube directions', 'I'], ['Bot lamp', 'L'],
|
||||
['Pick the piece under the cursor (with its direction and settings)', 'Middle mouse'], ['Notebook', 'N'], ['Clear all blueprint ghosts', 'Delete'], ['Save', 'Ctrl + S'], ['Pause · menu', 'Esc'], ['Mute', 'M'],
|
||||
];
|
||||
const pad = [
|
||||
['Fly', 'Left stick'], ['Boost', 'Left stick pushed all the way'], ['Aim', 'Right stick'], ['Use tool · suck', 'RT'], ['Second action · blow', 'LT'], ['Tools', 'LB / RB'],
|
||||
['Cycle what you blow · piece', 'D-pad ← →'], ['Brush size', 'D-pad ↑ ↓'], ['Interact', 'A'], ['Variant · mark material', 'X'], ['Pick-up mode (Vacuum)', 'B'], ['Thermal lens', 'Y'],
|
||||
['Cycle what you blow · piece', 'D-pad ← →'], ['Brush size', 'D-pad ↑ ↓'], ['Interact', 'A'], ['Variant · mark material', 'X'], ['Thermal lens', 'Y'],
|
||||
['Cancel', 'B'], ['Zoom', 'R3'], ['Lamp', 'L3'], ['Notebook', 'View / Back'], ['Menu', 'Menu / Start'],
|
||||
];
|
||||
const tools = [
|
||||
['1 Resonance drill', 'Hold left click to send pulses from the bot toward the cursor: rock they shake hard enough shatters and falls as rubble, ore, coal or scrap, and trees come apart into wood chunks and acorns. Q and E set the pulse width: narrow bores a tunnel fast, wide clears a big cone slowly, medium is in between. R over a material tunes the drill to it, so only that shatters (great for pulling a vein out of the rock); R again untunes. Built blocks are never harmed. Better bits dig harder rock, faster and further.'],
|
||||
['2 Vacuum', 'Left click picks up what you click, only marked materials, or everything: T or the card chip changes the mode. R over a grain or ⬇ in the bag marks it for pick-up. Adding a mark switches to Only marked; removing the last returns to What I click. Hold Shift while not flying to take everything. Right click blows the materials marked ⬆ in the bag as an even mix. Bars blow one at a time. Click a name or use Q/E to blow only one material; it stays chosen when empty. Pick-up and blow marks are separate.'],
|
||||
['2 Vacuum', 'Left click picks up everything, or only marked materials once you mark some. F opens the vacuum menu to mark what to pick up (⬇) and blow (⬆). R over a grain marks it. Hold Shift while not flying to take everything. Right click blows the ⬆ materials as an even mix, bars one at a time. Click a bag name or use Q/E to blow only one; it stays chosen when empty.'],
|
||||
['3 Build', 'Places pieces on a grid of 4×4 blocks: wall blocks, belts, tubes, filters, grates, gates, pipes, pumps and outlets, machines (fans, the Refiner) and molds. Drag for a line, hold Shift while dragging for a filled rectangle. Right click takes a piece back. Your bot flies through anything you build.'],
|
||||
['4 Igniter', 'Heats a small spot to 640°C, and its flame reaches a few grains into a pile. Enough to light coal and wood that touch air.'],
|
||||
['Copy, cut and paste', 'Hold C (copy) or X (cut) and drag a box over what you built; let go and it is picked up, ready to paste. Cut takes it down and refunds it to your bag. Click to place ghosts: your bot builds them from your bag when it is close. R flips, V pastes again, right click or Esc stops. Ctrl+Z undoes building. The notebook (B) keeps saved blueprints and a few starter designs.'],
|
||||
@@ -191,9 +191,9 @@ function controlsHtml() {
|
||||
<p class="label grouphead">Keyboard and mouse</p>${tbl(kb)}<p class="label grouphead">Gamepad</p>${tbl(pad)}
|
||||
<p class="label grouphead">First steps</p>
|
||||
<p class="note">1. Drill down a little. Stone falls as rubble; coal (dark seams), copper ore (green speckles) and clay (reddish) come loose too.<br>
|
||||
2. With the Vacuum, click on coal to suck up only coal, then the copper ore, rubble and clay you want.<br>
|
||||
2. With the Vacuum, left click to pick up loose materials. To take only coal, copper ore, rubble or clay, mark what you want in the vacuum menu (F).<br>
|
||||
3. Build (3) a chamber of stone wall blocks with a one-block vent in the roof, a floor of clay Grates, and an Ingot mold right under the grates. The notebook's Blueprints tab has this as a starter design.<br>
|
||||
4. Click coal in your bag, then mark copper ore with ⬆ to blow both. Fly inside (the bot passes through what you build) and right click to blow an even mix onto the grates: about 50 of each. (Ore first and coal on top works too; coal buried under ore will not light.) Light a coal grain on top with the Igniter.<br>
|
||||
4. In the vacuum menu (F), mark coal and copper ore with ⬆ to blow both. Fly inside (the bot passes through what you build) and right click to blow an even mix onto the grates: about 50 of each. (Ore first and coal on top works too; coal buried under ore will not light.) Light a coal grain on top with the Igniter.<br>
|
||||
5. When the ingot sets, bars drop out of the bottom of the mold onto whatever is under it. Leave one open block under it: a belt below that carries them off, or vacuum them up. Leftover metal stays for the next firing. 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.<br>
|
||||
Screw tubes carry grains and whole bars: feed bars in from a belt, turn corners and unload at the mouth.<br>
|
||||
6. Blow the bars into the trade dock: they sell the moment they drop through its grate, and bars pay far more than ore. Watch the Market page for orders that pay double. Money buys belts, screw tubes and fans; pay down the claim there too.<br>
|
||||
|
||||
+2
-2
@@ -153,9 +153,9 @@ 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.pickMode === 'first' && GAME.vacFilter > 0 ? [GAME.vacFilter] : GAME.lmb && GAME.pickMode === 'marked' && GAME.vacFilter >= 0 ? [...GAME.collect] : blowList();
|
||||
const swatches = GAME.lmb ? GAME.vacFilter >= 0 && GAME.collect.size ? [...GAME.collect] : [] : 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 && GAME.vacFilter)) {
|
||||
if (blowing || GAME.lmb) {
|
||||
// faint line from the nozzle: the path the grains take
|
||||
const c = worldToScreenPx(bot.x + bot.w / 2, bot.y + bot.h / 2);
|
||||
ctx.strokeStyle = blowing ? 'rgba(255,210,122,0.22)' : 'rgba(92,186,166,0.22)'; ctx.lineWidth = Math.max(1, zp * (r + 0.5) * 0.6);
|
||||
|
||||
+34
-27
@@ -53,23 +53,10 @@ function rotate() {
|
||||
else return;
|
||||
playSfx('ui'); hudDirty = true;
|
||||
}
|
||||
const PICK_MODES = ['first', 'marked', 'all'];
|
||||
const PICK_LABELS = { first: 'What I click', marked: 'Only marked', all: 'Everything' };
|
||||
function setPickMode(mode) {
|
||||
GAME.pickMode = mode;
|
||||
try { localStorage.setItem('deepgrain.pickMode', mode); } catch (e) { /* storage unavailable */ }
|
||||
hudDirty = true;
|
||||
}
|
||||
function cyclePickMode() {
|
||||
setPickMode(PICK_MODES[(PICK_MODES.indexOf(GAME.pickMode) + 1) % PICK_MODES.length]);
|
||||
playSfx('ui');
|
||||
}
|
||||
function toggleCollect(m) {
|
||||
if (!m) return;
|
||||
const add = !GAME.collect.has(m);
|
||||
if (add) GAME.collect.add(m); else GAME.collect.delete(m);
|
||||
if (add && GAME.pickMode !== 'marked') { setPickMode('marked'); setStatus('Picking up only marked materials.', 'info'); }
|
||||
else if (!GAME.collect.size && GAME.pickMode === 'marked') setPickMode('first');
|
||||
try { localStorage.setItem('deepgrain.collect', JSON.stringify([...GAME.collect])); } catch (e) { /* storage unavailable */ }
|
||||
lastBagKey = ''; hudDirty = true; playSfx('ui');
|
||||
}
|
||||
@@ -154,6 +141,34 @@ function openFilterPicker(cur, onDone, title) {
|
||||
box.querySelectorAll('[data-m]').forEach(b => b.onclick = () => { const m = +b.dataset.m; if (sel.has(m)) sel.delete(m); else sel.add(m); playSfx('ui'); sync(); });
|
||||
sync();
|
||||
}
|
||||
function openVacuumMenu() {
|
||||
ensureBlow();
|
||||
dialog('Vacuum', '', [
|
||||
{ label: 'Pick up everything', cls: 'ghost', fn: () => {
|
||||
GAME.collect.clear();
|
||||
try { localStorage.setItem('deepgrain.collect', '[]'); } catch (e) { /* storage unavailable */ }
|
||||
lastBagKey = ''; hudDirty = true; playSfx('ui'); sync(); return true;
|
||||
} },
|
||||
{ label: 'Blow one at a time', cls: 'ghost', fn: () => {
|
||||
GAME.blow = new Set(blowList().slice(0, 1));
|
||||
lastBagKey = ''; hudDirty = true; playSfx('ui'); sync(); return true;
|
||||
} },
|
||||
{ label: 'Done', cls: 'primary' },
|
||||
]);
|
||||
const box = $('dlg-body');
|
||||
function sync() {
|
||||
const list = BAG_ORDER.filter(m => bag[m] > 0)
|
||||
.concat(BAG_ORDER.filter(m => !bag[m] && (GAME.collect.has(m) || GAME.blow.has(m))))
|
||||
.concat(BAG_ORDER.filter(m => !bag[m] && !GAME.collect.has(m) && !GAME.blow.has(m) && seen[m] && filterable(m)));
|
||||
const blow = blowList();
|
||||
box.innerHTML = `<p class="note" id="vm-sum">${esc(GAME.collect.size ? 'Picking up only ' + matList([...GAME.collect]) + '.' : 'Picking up everything.')} Blowing out ${blow.length > 1 ? `an even mix of ${blow.length}` : blow.length ? esc(MD[blow[0]].name.toLowerCase()) : 'nothing'}.</p>`
|
||||
+ (!GAME.collect.size ? '<p class="note">Mark materials to pick up only those.</p>' : '')
|
||||
+ (list.length ? `<div class="vpick">${list.map(m => `<div class="wp"><span class="sw" style="background:${rgbOf(m)}"></span><span><b>${esc(MD[m].name)}</b><span>${bag[m] ? `you have ${bag[m].toLocaleString('en-US')}` : 'none in bag'}</span><div class="vtoggles"><button data-vm-pick="${m}" aria-pressed="${GAME.collect.has(m)}" class="btn ${GAME.collect.has(m) ? 'on' : ''}">⬇ Pick up</button><button data-vm-blow="${m}" aria-pressed="${GAME.blow.has(m)}" class="btn ${GAME.blow.has(m) ? 'on' : ''}"${!bag[m] && !GAME.blow.has(m) ? ' disabled' : ''}>⬆ Blow</button></div></span></div>`).join('')}</div>` : '<p class="note">Find something loose first.</p>');
|
||||
box.querySelectorAll('[data-vm-pick]').forEach(b => b.onclick = () => { toggleCollect(+b.dataset.vmPick); sync(); });
|
||||
box.querySelectorAll('[data-vm-blow]').forEach(b => b.onclick = () => { toggleBlow(+b.dataset.vmBlow); sync(); });
|
||||
}
|
||||
sync();
|
||||
}
|
||||
function openWallPicker() {
|
||||
const P = piece(), title = P.kind === 'mold' ? `${P.name} material` : 'Wall material';
|
||||
const list = WALL_LIST.filter(m => bag[m] > 0).concat(WALL_LIST.filter(m => !bag[m]));
|
||||
@@ -211,13 +226,12 @@ 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(), f = GAME.lmb && GAME.pickMode === 'first' ? GAME.vacFilter : 0;
|
||||
const marks = GAME.pickMode === 'marked' ? [...GAME.collect] : f > 0 ? [f] : [];
|
||||
const list = 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-pick-mode title="Cycle pick-up mode">${PICK_LABELS[GAME.pickMode]} · T</button>${sws(marks)}</div>
|
||||
<div class="row vacrow"><b>Blow out</b><kbd>Q</kbd>${sws(list)}<span class="name grow">${list.length > 1 ? `Mix of ${list.length}` : list.length ? esc(MD[list[0]].name) : 'bag empty'}</span><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. R marks what is under the cursor. Shift takes everything. <span class="chip">nozzle ${GAME.brush[1]}</span></div>`;
|
||||
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="sub">Left picks up, right blows out. F chooses what. R marks what is under the cursor. Shift takes 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>`;
|
||||
}
|
||||
@@ -240,10 +254,7 @@ function renderBag() {
|
||||
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 row = el('div', { class: 'bagrow' + (sel ? ' on' : '') });
|
||||
if (t === 'vacuum') {
|
||||
const down = el('button', { class: 'mark' + (GAME.collect.has(m) ? ' on' : ''), title: `Pick up ${MD[m].name}`, 'aria-label': `Pick up ${MD[m].name}`, 'aria-pressed': GAME.collect.has(m), 'data-pick': m }, '⬇');
|
||||
down.onclick = () => toggleCollect(m); row.appendChild(down);
|
||||
}
|
||||
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}` });
|
||||
b.innerHTML = `<span class="sw" style="background:${rgbOf(m)}"></span><span class="nm">${esc(MD[m].name)}</span><span class="n num">${bag[m].toLocaleString('en-US')}</span>`;
|
||||
b.onclick = () => {
|
||||
@@ -253,11 +264,7 @@ function renderBag() {
|
||||
hudDirty = true; lastBagKey = ''; playSfx('ui');
|
||||
};
|
||||
row.appendChild(b);
|
||||
if (t === 'vacuum') {
|
||||
const up = el('button', { class: 'mark' + (GAME.blow.has(m) ? ' on' : ''), title: `Blow out ${MD[m].name}`, 'aria-label': `Blow out ${MD[m].name}`, 'aria-pressed': GAME.blow.has(m), 'data-blow': m }, '⬆');
|
||||
up.onclick = () => toggleBlow(m); row.appendChild(up);
|
||||
}
|
||||
box.appendChild(row);
|
||||
}
|
||||
if (t === 'vacuum') box.appendChild(el('div', { class: 'baghint' }, '⬇ what you pick up · ⬆ what you blow out · click a name to blow only that'));
|
||||
if (t === 'vacuum') box.appendChild(el('div', { class: 'baghint' }, 'F with the Vacuum: choose what to pick up and blow'));
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ function startNewWorld(seed, w, h, name = '') {
|
||||
GAME.playTime = 0; GAME.clip = null; GAME.paste = false; GAME.selDrag = null; GAME.tool = 0; GAME.blow.clear(); GAME.wallMat = RSTONE; GAME.filterCfg = { m: [], inv: 0 }; GAME.pieceIdx = 0;
|
||||
showLoading(false);
|
||||
enterGame();
|
||||
showCard({ kind: 'Welcome', title: 'The dig site', body: ['Fly with WASD. The Drill (1) breaks rock loose. The Vacuum (2) sucks up what you click on and blows it back out with right click.', 'You owe $20,000 on this claim. Sell what you dig and make at the trade dock next to you: anything that drops through its grate is paid for on the spot, and buyers post orders that pay far more. Every tip lives in the notebook (N).'], hold: 1.8 });
|
||||
showCard({ kind: 'Welcome', title: 'The dig site', body: ['Fly with WASD. The Drill (1) breaks rock loose. The Vacuum (2) picks up everything, or only what you mark in its menu (F). Right click blows materials back out.', 'You owe $20,000 on this claim. Sell what you dig and make at the trade dock next to you: anything that drops through its grate is paid for on the spot, and buyers post orders that pay far more. Every tip lives in the notebook (N).'], hold: 1.8 });
|
||||
await saveWorld('auto');
|
||||
} catch (e) { showLoading(false); toast('Could not create a world. Browser storage is unavailable.'); }
|
||||
}, 30);
|
||||
|
||||
+1
-3
@@ -39,13 +39,11 @@ const BAG_ORDER = [BARAU, BARAG, BARBZ, BARBS, BARST, BARFE, BARCU, BARSN, BARZN
|
||||
function loadCollect() { try { const a = JSON.parse(localStorage.getItem('deepgrain.collect') || '[]'); return new Set(a.filter(m => m > 0 && m < NMAT && BAGOK[m])); } catch (e) { return new Set(); } }
|
||||
const GAME = {
|
||||
running: false, paused: false, tool: 0, blow: new Set(), wallMat: RSTONE, filterCfg: { m: [], inv: 0 }, pieceIdx: 0, pieceDir: {},
|
||||
brush: [3, 2, 0, 0, 0], collect: loadCollect(), tipsOpen: new Set(), cards: [], vacFilter: 0, vacLocked: false, rmbConsumed: false, rmbSeen: new Set(), lookHold: { x: 0, y: 0 },
|
||||
brush: [3, 2, 0, 0, 0], collect: loadCollect(), tipsOpen: new Set(), cards: [], vacFilter: 0, rmbConsumed: false, rmbSeen: new Set(), lookHold: { x: 0, y: 0 },
|
||||
paste: false, selDrag: null, rmbRec: null, dragDir: -1, replaceShown: false, clip: null, drag: null, aim: { x: 0, y: 0 }, mouse: { x: 0, y: 0, in: false },
|
||||
lmb: false, rmb: false, drillW: 1, drillTune: 0, lastDug: 0, padRun: 0, status: '', statusKind: 'err', statusT: 0, usingPad: false, padAim: { x: 12, y: 0 },
|
||||
lastAutosave: 0, playTime: 0, lastHud: 0, worldId: '', worldName: '',
|
||||
};
|
||||
try { GAME.pickMode = localStorage.getItem('deepgrain.pickMode'); } catch (e) { /* storage unavailable */ }
|
||||
if (!['first', 'marked', 'all'].includes(GAME.pickMode)) GAME.pickMode = GAME.collect.size ? 'marked' : 'first';
|
||||
const keys = new Set();
|
||||
let hudDirty = true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user