Vacuum controls: pick-up modes and separate pick-up and blow marks in the bag (t6, t15)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+48
-37
@@ -21,13 +21,10 @@ function cycleItem(d) {
|
||||
const t = toolId();
|
||||
if (t === 'drill') { setDrillWidth(GAME.drillW + d); return; }
|
||||
if (t === 'vacuum') {
|
||||
// what right click blows: each material in the bag, plus an even mix of the ticked ones
|
||||
const l = bagMaterials().map(String);
|
||||
if (mixList().length >= 2) l.push('mix');
|
||||
const l = bagMaterials();
|
||||
if (!l.length) return;
|
||||
let k = l.indexOf(GAME.blowMix ? 'mix' : String(GAME.dropMat)); k = (k + d + l.length) % l.length; if (k < 0) k = 0;
|
||||
if (l[k] === 'mix') GAME.blowMix = true; else { GAME.blowMix = false; GAME.dropMat = +l[k]; }
|
||||
GAME.matChosen = true;
|
||||
const k = l.indexOf(blowList()[0]);
|
||||
GAME.blow = new Set([l[(k + d + l.length) % l.length]]);
|
||||
} else if (t === 'build') {
|
||||
let k = BUILD_ORDER.indexOf(piece().id); k = (k + d + BUILD_ORDER.length) % BUILD_ORDER.length;
|
||||
GAME.pieceIdx = PIECE_BY_ID[BUILD_ORDER[k]].index; GAME.buildCat = catOf(BUILD_ORDER[k]);
|
||||
@@ -56,12 +53,32 @@ 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;
|
||||
if (GAME.collect.has(m)) GAME.collect.delete(m); else GAME.collect.add(m);
|
||||
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');
|
||||
}
|
||||
function toggleBlow(m) {
|
||||
if (GAME.blow.has(m)) GAME.blow.delete(m);
|
||||
else if (PH[m] === PH_ITEM) GAME.blow = new Set([m]);
|
||||
else { for (const k of GAME.blow) if (PH[k] === PH_ITEM) GAME.blow.delete(k); GAME.blow.add(m); }
|
||||
lastBagKey = ''; hudDirty = true; playSfx('ui');
|
||||
}
|
||||
function pickFilterUnderCursor() {
|
||||
const ax = Math.floor(GAME.aim.x), ay = Math.floor(GAME.aim.y);
|
||||
const bar = ents.find(e => ax >= e.ix && ax < e.ix + BAR_W && ay >= e.iy && ay < e.iy + BAR_H);
|
||||
@@ -78,9 +95,8 @@ function toggleFilterMat(m) {
|
||||
}
|
||||
function toggleCollectUnderCursor() {
|
||||
const m = grainAt(Math.floor(GAME.aim.x), Math.floor(GAME.aim.y));
|
||||
if (!m) { setStatus('Aim at something loose to tick it.', 'info'); return; }
|
||||
if (!m) { setStatus('Aim at something loose to mark it.', 'info'); return; }
|
||||
toggleCollect(m);
|
||||
setStatus(`${MD[m].name} ${GAME.collect.has(m) ? 'ticked for vacuuming' : 'unticked'}.`, 'info');
|
||||
}
|
||||
function setBrush(d) {
|
||||
const t = toolId();
|
||||
@@ -194,18 +210,14 @@ function renderSelCard() {
|
||||
+ '<div class="sub">Place pieces from the menu below. Drag for a line, <kbd>Shift</kbd>-drag for a box; out of reach becomes ghosts.</div>'
|
||||
+ '<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') {
|
||||
ensureDropMat();
|
||||
const m = GAME.dropMat, f = GAME.lmb ? GAME.vacFilter : 0;
|
||||
const list = [...GAME.collect];
|
||||
const mixL = mixList();
|
||||
const blowRow = GAME.blowMix ? `<div class="row cycle"><kbd>Q</kbd>${mixL.map(k => `<span class="sw" style="background:${rgbOf(k)}"></span>`).join('')}<span class="name grow">Ticked mix</span><span class="num chip">${mixL.reduce((a, k) => a + bag[k], 0).toLocaleString('en-US')}</span><kbd>E</kbd></div>`
|
||||
: m ? `<div class="row cycle"><kbd>Q</kbd><span class="sw" style="background:${rgbOf(m)}"></span><span class="name grow">${esc(MD[m].name)}</span><span class="num chip ${bag[m] ? '' : 'bad'}">${bag[m] ? bag[m].toLocaleString('en-US') : 'none left'}</span><kbd>E</kbd></div>`
|
||||
: `<div class="row"><span class="name">Vacuum</span><span class="sub">bag empty</span></div>`;
|
||||
const sucking = f < 0 ? 'everything' : list.length ? 'only the ticked materials' : f > 0 ? 'only ' + esc(MD[f].name.toLowerCase()) : 'what you start on';
|
||||
h = `${blowRow}
|
||||
<div class="sub"><b>Left</b> sucks up ${sucking}${list.length && f >= 0 ? ' (untick them all to pick by what you click on)' : ''}. Standing still, <kbd>Shift</kbd> takes everything.</div>
|
||||
<div class="sub"><b>Right</b> blows ${GAME.blowMix ? 'an even mix of the ticked materials' : m ? 'only ' + esc(MD[m].name.toLowerCase()) : 'the chosen material'} out. ${mixL.length > 1 || GAME.blowMix ? '<kbd>Q</kbd>/<kbd>E</kbd> switch between single materials and the ticked mix.' : 'Tick 2+ materials to blow them as a mix.'}</div>
|
||||
<div class="row" style="flex-wrap:wrap;gap:4px"><span class="chip">nozzle ${GAME.brush[1]}</span>${list.map(k => `<span class="chip"><span class="sw" style="display:inline-block;vertical-align:-2px;width:9px;height:9px;margin-right:4px;background:${rgbOf(k)}"></span>${esc(MD[k].name)}</span>`).join('')}${list.length ? '' : '<span class="sub">Nothing ticked. <kbd>R</kbd> ticks what is under the cursor.</span>'}</div>`;
|
||||
ensureBlow();
|
||||
const list = blowList(), f = GAME.lmb && GAME.pickMode === 'first' ? GAME.vacFilter : 0;
|
||||
const marks = GAME.pickMode === 'marked' ? [...GAME.collect] : f > 0 ? [f] : [];
|
||||
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>`;
|
||||
} 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>`;
|
||||
}
|
||||
@@ -218,35 +230,34 @@ function renderBag() {
|
||||
$('bagcap').textContent = `${bagTotal.toLocaleString('en-US')} / ${cap.toLocaleString('en-US')}`;
|
||||
$('bagbar').firstChild.style.width = pct + '%';
|
||||
$('bagbar').classList.toggle('full', bagTotal >= cap);
|
||||
const l = BAG_ORDER.filter(m => bag[m] > 0 || GAME.collect.has(m));
|
||||
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' : '')).join(',') + '|' + GAME.dropMat + '|' + GAME.blowMix + '|' + GAME.wallMat + '|' + GAME.filterCfg.m.join('.') + '|' + t + '|' + GAME.pieceIdx;
|
||||
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;
|
||||
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.blowMix ? GAME.collect.has(m) : m === GAME.dropMat)) || (t === 'build' && m === GAME.wallMat && pieceUsesWall(piece())) || (t === 'build' && piece().filter && GAME.filterCfg.m.includes(m));
|
||||
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' : '') });
|
||||
const tick = el('button', { class: 'tick' + (GAME.collect.has(m) ? ' on' : ''), title: GAME.collect.has(m) ? 'Ticked: the vacuum takes only ticked materials, and they make up the Ticked mix' : 'Tick to vacuum only ticked materials', 'aria-label': `Tick ${MD[m].name}`, 'aria-pressed': GAME.collect.has(m) });
|
||||
tick.onclick = () => toggleCollect(m);
|
||||
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);
|
||||
}
|
||||
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 = () => {
|
||||
if (t === 'build' && piece().filter && filterable(m)) { toggleFilterMat(m); return; }
|
||||
else if (t === 'build' && WALL_OF[m]) { GAME.wallMat = m; if (!pieceUsesWall(piece())) GAME.pieceIdx = 0; }
|
||||
else { GAME.dropMat = m; GAME.matChosen = true; GAME.blowMix = false; if (t !== 'vacuum') selectTool(1); }
|
||||
else { GAME.blow = new Set([m]); if (t !== 'vacuum') selectTool(1); }
|
||||
hudDirty = true; lastBagKey = ''; playSfx('ui');
|
||||
};
|
||||
row.appendChild(tick); row.appendChild(b); box.appendChild(row);
|
||||
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' && mixList().length > 1) {
|
||||
// the ticked mix is a choice of its own, like any material
|
||||
const mx = mixList(), row = el('div', { class: 'bagrow mixrow' + (GAME.blowMix ? ' on' : '') });
|
||||
const b = el('button', { class: 'pick', title: 'Blow an even mix of the ticked materials' });
|
||||
b.innerHTML = `<span class="mixsw">${mx.slice(0, 4).map(k => `<span class="sw" style="background:${rgbOf(k)}"></span>`).join('')}</span><span class="nm">Ticked mix</span><span class="n num">${mx.reduce((a, k) => a + bag[k], 0).toLocaleString('en-US')}</span>`;
|
||||
b.onclick = () => { GAME.blowMix = true; GAME.matChosen = true; hudDirty = true; lastBagKey = ''; playSfx('ui'); };
|
||||
row.appendChild(b); box.appendChild(row);
|
||||
}
|
||||
if (t === 'vacuum') box.appendChild(el('div', { class: 'baghint' }, 'Click a material to blow only that, or Ticked mix to blow an even mix of the ticked ones. Ticked ones always come along when you vacuum.'));
|
||||
if (t === 'vacuum') box.appendChild(el('div', { class: 'baghint' }, '⬇ what you pick up · ⬆ what you blow out · click a name to blow only that'));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user