// Selection pickers: filter rules, filter settings and wall materials. // What a filter can hold: loose things and bars you have found, plus anything it already holds function filterChoices(cur) { return BAG_ORDER.filter(m => filterable(m) && (seen[m] || cur.includes(m))); } function matList(ms) { const n = ms.map(m => MD[m].name.toLowerCase()); return n.length <= 3 ? n.join(n.length === 2 ? ' and ' : ', ') : `${n.slice(0, 2).join(', ')} and ${n.length - 2} more`; } // What a filter does, in words: what falls through and what rides along function filterParts(f) { if (!f.m.length) return f.inv ? { drops: 'everything', rides: 'nothing' } : { drops: 'nothing', rides: 'everything' }; return f.inv ? { drops: 'everything else', rides: matList(f.m) } : { drops: matList(f.m), rides: 'everything else' }; } function filterSentence(f) { const p = filterParts(f); return `drop ${p.drops} and carry ${p.rides}`; } // Change the whole run of matching filters at once function applyFilterRun(run, f) { undoRecord('filter settings', () => { for (const b of run) { undoNote({ t: 'filter', bx: b % BW, by: (b / BW) | 0, v: blockV[b], extra: filterInfo(b) }); blockV[b] = filterVariant(blockP[b], f.dir ? 128 : 0); setFilter(b, f); } }); filtersDirty = true; } function openFilterPicker(cur, onDone, title) { const sel = new Set(cur.m); let inv = cur.inv ? 1 : 0, dir = beltGrade(cur.code) ? (beltGrade(cur.code)>0 ? 1 : 0) : cur.dir ? 1 : 0; const list = filterChoices(cur.m); const body = `
Screen travel${beltGrade(cur.code) ? `${esc(beltDirection(cur.code, dir << 7))}` : ''}
` + (list.length ? `
${list.map(m => ``).join('')}
` : '

Find something loose first.

') + `

`; dialog(title || 'Filter', body, [{ label: 'Clear', cls: 'ghost', fn: () => { sel.clear(); sync(); return true; } }, { label: 'Cancel' }, { label: 'Set filter', cls: 'primary', fn: () => { onDone({ m: [...sel].sort((a, b) => a - b), inv, dir }); hudDirty = true; } }]); const box = $('dlg-body'); function sync() { box.querySelectorAll('[data-inv]').forEach(b => { const on = +b.dataset.inv === inv; b.classList.toggle('on', on); b.setAttribute('aria-checked', on); }); box.querySelectorAll('[data-dir]').forEach(b => { const on = +b.dataset.dir === dir; b.classList.toggle('on', on); b.setAttribute('aria-checked', on); }); box.querySelectorAll('[data-m]').forEach(b => { const on = sel.has(+b.dataset.m); b.classList.toggle('on', on); b.setAttribute('aria-checked', on); }); const f = { m: [...sel].sort((a, b) => a - b), inv }; box.querySelector('#fp-sum').textContent = `${title && /in this row/.test(title) ? 'These filters' : 'This filter'} will ${filterSentence(f)}, ${beltGrade(cur.code) ? beltDirection(cur.code, dir << 7) : dir ? 'right' : 'left'}.`; } box.querySelectorAll('[data-dir]').forEach(b => b.onclick = () => { dir = +b.dataset.dir; playSfx('ui'); sync(); }); box.querySelectorAll('[data-inv]').forEach(b => b.onclick = () => { inv = +b.dataset.inv; playSfx('ui'); sync(); }); 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 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])); const body = `
${list.map(m => { const d = MD[WALL_OF[m]], cost = pieceCostNow(P, m), on = m === GAME.wallMat; // two sources build the same wall (glass from shards or from bars): say which const name = WALL_LIST.filter(k => WALL_OF[k] === WALL_OF[m]).length > 1 ? `${d.name} from ${MD[m].name.toLowerCase()}` : d.name; const heat = d.ign ? `burns at ${fmtT(d.ign)}` : d.melt ? `melts at ${fmtT(d.melt)}` : "won't melt"; return ``; }).join('')}
`; dialog(title, body, [{ label: 'Cancel' }]); $('dlg-body').querySelectorAll('[data-wall]').forEach(b => b.onclick = () => { GAME.wallMat = +b.dataset.wall; closeModal('m-dialog'); playSfx('ui'); hudDirty = true; lastBagKey = ''; setStatus(`${P.kind === 'mold' ? P.name : 'Walls'}: ${MD[WALL_OF[GAME.wallMat]].name.toLowerCase()}.`, 'info'); }); }