From badfcde640895e9b1a17b555f6317ff928c10e77 Mon Sep 17 00:00:00 2001 From: GaboGG Date: Sun, 26 Jul 2026 12:42:56 -0400 Subject: [PATCH] v0.13.3 - Auto-sell/salvage preset on settings page - New settings-page.js: adds a toolbar above the auto-salvage table on Character Settings (ss=se) with bulk preset buttons - Preset 1: Sell <=Fair (value 2) / Salvage <=Average (value 3) - Preset 2: Sell <=Crude (value 1) / Salvage <=Fair (value 2) - Disable All: reset both to No Auto-Sell/Salvage - Shows current state summary (Sell X | Salvage Y) - Also fixes init.js and build.sh to include new file --- scripts/build.sh | 1 + scripts/hv-unified.user.js | 124 +++++++++++++++++++++++++++++++++++++ scripts/latest.user.js | 124 +++++++++++++++++++++++++++++++++++++ src/init.js | 1 + src/settings-page.js | 101 ++++++++++++++++++++++++++++++ 5 files changed, 351 insertions(+) create mode 100644 src/settings-page.js diff --git a/scripts/build.sh b/scripts/build.sh index 5c0f67c..fdc6dcc 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -33,6 +33,7 @@ FILES=( armory.js battle-logger.js re-timer.js + settings-page.js public-api.js init.js ) diff --git a/scripts/hv-unified.user.js b/scripts/hv-unified.user.js index 366cec5..6ec9ec1 100644 --- a/scripts/hv-unified.user.js +++ b/scripts/hv-unified.user.js @@ -2789,6 +2789,27 @@ function enhanceArmory() { clear.onclick = clearAll; toolbar.appendChild(clear); + // Select All / Invert Selection (useful on any screen) + const selAll = document.createElement('input'); + selAll.type = 'button'; + selAll.value = '☐ All'; + selAll.style.cssText = 'padding:2px 6px;cursor:pointer;background:#3a4a6a;color:#fff;border:none;border-radius:3px;font-size:10px'; + selAll.onclick = () => { + items.forEach(item => { item.checkbox.checked = true; }); + if (typeof update_selected_count === 'function') update_selected_count(); + }; + toolbar.appendChild(selAll); + + const invert = document.createElement('input'); + invert.type = 'button'; + invert.value = '⊞ Invert'; + invert.style.cssText = 'padding:2px 6px;cursor:pointer;background:#444;color:#fff;border:none;border-radius:3px;font-size:10px'; + invert.onclick = () => { + items.forEach(item => { item.checkbox.checked = !item.checkbox.checked; }); + if (typeof update_selected_count === 'function') update_selected_count(); + }; + toolbar.appendChild(invert); + // ── Insert into page ── const eqSelect = document.getElementById('equipselect_outer') || document.querySelector('#equipselect_left, #armory_right > div'); @@ -2965,6 +2986,108 @@ function updateRETimer() { } } +// ── Settings page: auto-sell/salvage defaults ── + +function enhanceSettings() { + if (document.getElementById('hv-settings-enh')) return; + + const autoTable = document.getElementById('settings_autosalvage'); + if (!autoTable) return; + + // Check current state + const rows = []; + $$('tr', autoTable).forEach(tr => { + const sellSelect = tr.querySelector('select[name^="as_c_"]'); + const salvSelect = tr.querySelector('select[name^="as_s_"]'); + if (!sellSelect || !salvSelect) return; + const itemName = (tr.querySelector('td:first-child')?.textContent || '').trim(); + rows.push({ + name: itemName, + sell: sellSelect, + salv: salvSelect, + sellVal: parseInt(sellSelect.value), + salvVal: parseInt(salvSelect.value), + }); + }); + + if (rows.length === 0) return; + + // Build toolbar + const bar = document.createElement('div'); + bar.id = 'hv-settings-enh'; + bar.style.cssText = css({ + margin: '8px 0', + padding: '6px 8px', + background: '#1a1a2e', + borderRadius: '4px', + fontSize: '10px', + fontFamily: 'monospace', + display: 'flex', + gap: '4px', + flexWrap: 'wrap', + alignItems: 'center', + border: '1px solid #374151', + }); + + const label = document.createElement('span'); + label.style.cssText = 'color:#fdcb00;font-weight:bold;margin-right:6px'; + label.textContent = '⚙ Auto-Sell/Salvage'; + bar.appendChild(label); + + // Preset: Sell Fair (2), Salvage Average (3) + const preset1 = document.createElement('input'); + preset1.type = 'button'; + preset1.value = '💰 Sell ≤Fair / ♻ Salvage ≤Average'; + preset1.style.cssText = 'padding:3px 8px;cursor:pointer;background:#2a5a2a;color:#fff;border:none;border-radius:3px;font-size:10px'; + preset1.onclick = () => applyPreset(rows, 2, 3); + bar.appendChild(preset1); + + // Preset: Sell Crude (1), Salvage Fair (2) — more conservative + const preset2 = document.createElement('input'); + preset2.type = 'button'; + preset2.value = '💰 Sell ≤Crude / ♻ Salvage ≤Fair'; + preset2.style.cssText = 'padding:3px 8px;cursor:pointer;background:#5a3a2a;color:#fff;border:none;border-radius:3px;font-size:10px'; + preset2.onclick = () => applyPreset(rows, 1, 2); + bar.appendChild(preset2); + + // Reset to No Auto-Sell/Salvage + const resetBtn = document.createElement('input'); + resetBtn.type = 'button'; + resetBtn.value = '✗ Disable All'; + resetBtn.style.cssText = 'padding:3px 8px;cursor:pointer;background:#555;color:#fff;border:none;border-radius:3px;font-size:10px'; + resetBtn.onclick = () => applyPreset(rows, 0, 0); + bar.appendChild(resetBtn); + + // Summary of current state + const summary = document.createElement('span'); + summary.style.cssText = 'color:#888;margin-left:6px'; + const sellVals = rows.map(r => r.sellVal); + const salvVals = rows.map(r => r.salvVal); + const minSell = Math.min(...sellVals); + const minSalv = Math.min(...salvVals); + const maxSell = Math.max(...sellVals); + const maxSalv = Math.max(...salvVals); + const sellLabel = minSell === maxSell ? VAL_LABELS_SELL[minSell] : 'mixed'; + const salvLabel = minSalv === maxSalv ? VAL_LABELS_SALV[minSalv] : 'mixed'; + summary.textContent = `Current: Sell ${sellLabel} | Salvage ${salvLabel}`; + bar.appendChild(summary); + + // Insert above the auto-salvage table + autoTable.parentNode.insertBefore(bar, autoTable); + + function applyPreset(rows, sellVal, salvVal) { + rows.forEach(r => { + r.sell.value = sellVal; + r.salv.value = salvVal; + }); + // Update summary + summary.textContent = `Current: Sell ${VAL_LABELS_SELL[sellVal]} | Salvage ${VAL_LABELS_SALV[salvVal]}`; + } +} + +const VAL_LABELS_SELL = ['Off', 'Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary']; +const VAL_LABELS_SALV = ['Off', 'Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary']; + // ═══════════════════════════════════════════════════════════════════════ // PUBLIC API — window.HV for console power users // ═══════════════════════════════════════════════════════════════════════ @@ -3015,6 +3138,7 @@ function init() { if (STATE.page === 'monsterlab') { enhanceMonsterLab(); autoCheckTask('feed'); } if (STATE.page === 'arena') { autoCheckTask('arenas'); autoCheckTask('first-blood'); } if (STATE.page === 'character') showGuidancePanel(); + if (STATE.page === 'settings') enhanceSettings(); if (STATE.page === 'armory') enhanceArmory(); if (STATE.page === 'abilities') enhanceAbilities(); if (STATE.page === 'monster') enhanceMonsterLab(); diff --git a/scripts/latest.user.js b/scripts/latest.user.js index 366cec5..6ec9ec1 100644 --- a/scripts/latest.user.js +++ b/scripts/latest.user.js @@ -2789,6 +2789,27 @@ function enhanceArmory() { clear.onclick = clearAll; toolbar.appendChild(clear); + // Select All / Invert Selection (useful on any screen) + const selAll = document.createElement('input'); + selAll.type = 'button'; + selAll.value = '☐ All'; + selAll.style.cssText = 'padding:2px 6px;cursor:pointer;background:#3a4a6a;color:#fff;border:none;border-radius:3px;font-size:10px'; + selAll.onclick = () => { + items.forEach(item => { item.checkbox.checked = true; }); + if (typeof update_selected_count === 'function') update_selected_count(); + }; + toolbar.appendChild(selAll); + + const invert = document.createElement('input'); + invert.type = 'button'; + invert.value = '⊞ Invert'; + invert.style.cssText = 'padding:2px 6px;cursor:pointer;background:#444;color:#fff;border:none;border-radius:3px;font-size:10px'; + invert.onclick = () => { + items.forEach(item => { item.checkbox.checked = !item.checkbox.checked; }); + if (typeof update_selected_count === 'function') update_selected_count(); + }; + toolbar.appendChild(invert); + // ── Insert into page ── const eqSelect = document.getElementById('equipselect_outer') || document.querySelector('#equipselect_left, #armory_right > div'); @@ -2965,6 +2986,108 @@ function updateRETimer() { } } +// ── Settings page: auto-sell/salvage defaults ── + +function enhanceSettings() { + if (document.getElementById('hv-settings-enh')) return; + + const autoTable = document.getElementById('settings_autosalvage'); + if (!autoTable) return; + + // Check current state + const rows = []; + $$('tr', autoTable).forEach(tr => { + const sellSelect = tr.querySelector('select[name^="as_c_"]'); + const salvSelect = tr.querySelector('select[name^="as_s_"]'); + if (!sellSelect || !salvSelect) return; + const itemName = (tr.querySelector('td:first-child')?.textContent || '').trim(); + rows.push({ + name: itemName, + sell: sellSelect, + salv: salvSelect, + sellVal: parseInt(sellSelect.value), + salvVal: parseInt(salvSelect.value), + }); + }); + + if (rows.length === 0) return; + + // Build toolbar + const bar = document.createElement('div'); + bar.id = 'hv-settings-enh'; + bar.style.cssText = css({ + margin: '8px 0', + padding: '6px 8px', + background: '#1a1a2e', + borderRadius: '4px', + fontSize: '10px', + fontFamily: 'monospace', + display: 'flex', + gap: '4px', + flexWrap: 'wrap', + alignItems: 'center', + border: '1px solid #374151', + }); + + const label = document.createElement('span'); + label.style.cssText = 'color:#fdcb00;font-weight:bold;margin-right:6px'; + label.textContent = '⚙ Auto-Sell/Salvage'; + bar.appendChild(label); + + // Preset: Sell Fair (2), Salvage Average (3) + const preset1 = document.createElement('input'); + preset1.type = 'button'; + preset1.value = '💰 Sell ≤Fair / ♻ Salvage ≤Average'; + preset1.style.cssText = 'padding:3px 8px;cursor:pointer;background:#2a5a2a;color:#fff;border:none;border-radius:3px;font-size:10px'; + preset1.onclick = () => applyPreset(rows, 2, 3); + bar.appendChild(preset1); + + // Preset: Sell Crude (1), Salvage Fair (2) — more conservative + const preset2 = document.createElement('input'); + preset2.type = 'button'; + preset2.value = '💰 Sell ≤Crude / ♻ Salvage ≤Fair'; + preset2.style.cssText = 'padding:3px 8px;cursor:pointer;background:#5a3a2a;color:#fff;border:none;border-radius:3px;font-size:10px'; + preset2.onclick = () => applyPreset(rows, 1, 2); + bar.appendChild(preset2); + + // Reset to No Auto-Sell/Salvage + const resetBtn = document.createElement('input'); + resetBtn.type = 'button'; + resetBtn.value = '✗ Disable All'; + resetBtn.style.cssText = 'padding:3px 8px;cursor:pointer;background:#555;color:#fff;border:none;border-radius:3px;font-size:10px'; + resetBtn.onclick = () => applyPreset(rows, 0, 0); + bar.appendChild(resetBtn); + + // Summary of current state + const summary = document.createElement('span'); + summary.style.cssText = 'color:#888;margin-left:6px'; + const sellVals = rows.map(r => r.sellVal); + const salvVals = rows.map(r => r.salvVal); + const minSell = Math.min(...sellVals); + const minSalv = Math.min(...salvVals); + const maxSell = Math.max(...sellVals); + const maxSalv = Math.max(...salvVals); + const sellLabel = minSell === maxSell ? VAL_LABELS_SELL[minSell] : 'mixed'; + const salvLabel = minSalv === maxSalv ? VAL_LABELS_SALV[minSalv] : 'mixed'; + summary.textContent = `Current: Sell ${sellLabel} | Salvage ${salvLabel}`; + bar.appendChild(summary); + + // Insert above the auto-salvage table + autoTable.parentNode.insertBefore(bar, autoTable); + + function applyPreset(rows, sellVal, salvVal) { + rows.forEach(r => { + r.sell.value = sellVal; + r.salv.value = salvVal; + }); + // Update summary + summary.textContent = `Current: Sell ${VAL_LABELS_SELL[sellVal]} | Salvage ${VAL_LABELS_SALV[salvVal]}`; + } +} + +const VAL_LABELS_SELL = ['Off', 'Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary']; +const VAL_LABELS_SALV = ['Off', 'Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary']; + // ═══════════════════════════════════════════════════════════════════════ // PUBLIC API — window.HV for console power users // ═══════════════════════════════════════════════════════════════════════ @@ -3015,6 +3138,7 @@ function init() { if (STATE.page === 'monsterlab') { enhanceMonsterLab(); autoCheckTask('feed'); } if (STATE.page === 'arena') { autoCheckTask('arenas'); autoCheckTask('first-blood'); } if (STATE.page === 'character') showGuidancePanel(); + if (STATE.page === 'settings') enhanceSettings(); if (STATE.page === 'armory') enhanceArmory(); if (STATE.page === 'abilities') enhanceAbilities(); if (STATE.page === 'monster') enhanceMonsterLab(); diff --git a/src/init.js b/src/init.js index 27c17c4..d87b1fb 100644 --- a/src/init.js +++ b/src/init.js @@ -24,6 +24,7 @@ function init() { if (STATE.page === 'monsterlab') { enhanceMonsterLab(); autoCheckTask('feed'); } if (STATE.page === 'arena') { autoCheckTask('arenas'); autoCheckTask('first-blood'); } if (STATE.page === 'character') showGuidancePanel(); + if (STATE.page === 'settings') enhanceSettings(); if (STATE.page === 'armory') enhanceArmory(); if (STATE.page === 'abilities') enhanceAbilities(); if (STATE.page === 'monster') enhanceMonsterLab(); diff --git a/src/settings-page.js b/src/settings-page.js new file mode 100644 index 0000000..2cb58b6 --- /dev/null +++ b/src/settings-page.js @@ -0,0 +1,101 @@ +// ── Settings page: auto-sell/salvage defaults ── + +function enhanceSettings() { + if (document.getElementById('hv-settings-enh')) return; + + const autoTable = document.getElementById('settings_autosalvage'); + if (!autoTable) return; + + // Check current state + const rows = []; + $$('tr', autoTable).forEach(tr => { + const sellSelect = tr.querySelector('select[name^="as_c_"]'); + const salvSelect = tr.querySelector('select[name^="as_s_"]'); + if (!sellSelect || !salvSelect) return; + const itemName = (tr.querySelector('td:first-child')?.textContent || '').trim(); + rows.push({ + name: itemName, + sell: sellSelect, + salv: salvSelect, + sellVal: parseInt(sellSelect.value), + salvVal: parseInt(salvSelect.value), + }); + }); + + if (rows.length === 0) return; + + // Build toolbar + const bar = document.createElement('div'); + bar.id = 'hv-settings-enh'; + bar.style.cssText = css({ + margin: '8px 0', + padding: '6px 8px', + background: '#1a1a2e', + borderRadius: '4px', + fontSize: '10px', + fontFamily: 'monospace', + display: 'flex', + gap: '4px', + flexWrap: 'wrap', + alignItems: 'center', + border: '1px solid #374151', + }); + + const label = document.createElement('span'); + label.style.cssText = 'color:#fdcb00;font-weight:bold;margin-right:6px'; + label.textContent = '⚙ Auto-Sell/Salvage'; + bar.appendChild(label); + + // Preset: Sell Fair (2), Salvage Average (3) + const preset1 = document.createElement('input'); + preset1.type = 'button'; + preset1.value = '💰 Sell ≤Fair / ♻ Salvage ≤Average'; + preset1.style.cssText = 'padding:3px 8px;cursor:pointer;background:#2a5a2a;color:#fff;border:none;border-radius:3px;font-size:10px'; + preset1.onclick = () => applyPreset(rows, 2, 3); + bar.appendChild(preset1); + + // Preset: Sell Crude (1), Salvage Fair (2) — more conservative + const preset2 = document.createElement('input'); + preset2.type = 'button'; + preset2.value = '💰 Sell ≤Crude / ♻ Salvage ≤Fair'; + preset2.style.cssText = 'padding:3px 8px;cursor:pointer;background:#5a3a2a;color:#fff;border:none;border-radius:3px;font-size:10px'; + preset2.onclick = () => applyPreset(rows, 1, 2); + bar.appendChild(preset2); + + // Reset to No Auto-Sell/Salvage + const resetBtn = document.createElement('input'); + resetBtn.type = 'button'; + resetBtn.value = '✗ Disable All'; + resetBtn.style.cssText = 'padding:3px 8px;cursor:pointer;background:#555;color:#fff;border:none;border-radius:3px;font-size:10px'; + resetBtn.onclick = () => applyPreset(rows, 0, 0); + bar.appendChild(resetBtn); + + // Summary of current state + const summary = document.createElement('span'); + summary.style.cssText = 'color:#888;margin-left:6px'; + const sellVals = rows.map(r => r.sellVal); + const salvVals = rows.map(r => r.salvVal); + const minSell = Math.min(...sellVals); + const minSalv = Math.min(...salvVals); + const maxSell = Math.max(...sellVals); + const maxSalv = Math.max(...salvVals); + const sellLabel = minSell === maxSell ? VAL_LABELS_SELL[minSell] : 'mixed'; + const salvLabel = minSalv === maxSalv ? VAL_LABELS_SALV[minSalv] : 'mixed'; + summary.textContent = `Current: Sell ${sellLabel} | Salvage ${salvLabel}`; + bar.appendChild(summary); + + // Insert above the auto-salvage table + autoTable.parentNode.insertBefore(bar, autoTable); + + function applyPreset(rows, sellVal, salvVal) { + rows.forEach(r => { + r.sell.value = sellVal; + r.salv.value = salvVal; + }); + // Update summary + summary.textContent = `Current: Sell ${VAL_LABELS_SELL[sellVal]} | Salvage ${VAL_LABELS_SALV[salvVal]}`; + } +} + +const VAL_LABELS_SELL = ['Off', 'Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary']; +const VAL_LABELS_SALV = ['Off', 'Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary'];