diff --git a/scripts/hv-unified.user.js b/scripts/hv-unified.user.js index a8ee740..d7da28f 100644 --- a/scripts/hv-unified.user.js +++ b/scripts/hv-unified.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name HV Unified // @namespace hvunified -// @version 0.14.11 +// @version 0.14.12 // @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse // @author GaboGG + Hermes // @match *://*.hentaiverse.org/* @@ -17,7 +17,7 @@ // CONFIG — default settings // ═══════════════════════════════════════════════════════════════════════ -const VERSION = '0.14.11'; +const VERSION = '0.14.12'; const CFG = { // — Battle automation @@ -3442,18 +3442,17 @@ function scrapeCharacterEquip() { }); // Read the popup box for the currently-displayed tooltip - const tooltip = parseTooltipPopup(); - - // Merge tooltip stats with the matching item - if (tooltip && tooltip.name) { - const matchIdx = scraped.findIndex(s => tooltip.name.includes(s.name) || s.name.includes(tooltip.name)); - if (matchIdx >= 0) { - scraped[matchIdx].stats = tooltip.stats; - } else if (scraped.length > 0) { - // If no match, attach to first item as extra info - scraped[0].tooltipStats = tooltip.stats; + // Note: popup_box only updates on actual hover; triggerAllTooltips + // may not work if equips.set is async. We still get names/IDs from slots. + try { + const tooltip = parseTooltipPopup(); + if (tooltip && tooltip.name && tooltip.name !== 'Popup Box') { + const matchIdx = scraped.findIndex(s => tooltip.name.includes(s.name) || s.name.includes(tooltip.name)); + if (matchIdx >= 0) { + scraped[matchIdx].stats = tooltip.stats; + } } - } + } catch (e) {} if (scraped.length > 0) { const db = getGearDB(); @@ -3563,20 +3562,66 @@ function triggerAllTooltips() { const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : slot.getAttribute('onmouseover') || ''; const idMatch = omo.match(/equips\.set\((\d+)/); if (idMatch && typeof equips !== 'undefined' && equips.set) { - // Trigger the tooltip - equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130); - - // Read the popup - const tooltip = parseTooltipPopup(); - if (tooltip && tooltip.name) { - results.push(tooltip); - } + try { + equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130); + } catch (e) {} } }); return results; } +// Manual: hover each item and capture tooltip stats with delays +// Run this from console on the character equipment page for full stats +function captureAllTooltips(delay = 400) { + const slots = document.querySelectorAll('#eqsb > .eqb'); + const results = []; + let idx = 0; + + function next() { + if (idx >= slots.length) { + console.log(`%c[HV] Captured ${results.length} tooltips`, 'color:#0f0'); + // Re-scrape with the captured data + autoScrapeGear(); + return; + } + + const slot = slots[idx]; + const nameDiv = slot.querySelector(':scope > div[onmouseover]'); + const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : ''; + const idMatch = omo.match(/equips\.set\((\d+)/); + + if (idMatch && typeof equips !== 'undefined' && equips.set) { + try { + equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130); + // Wait for popup to populate + setTimeout(() => { + const tooltip = parseTooltipPopup(); + if (tooltip && tooltip.name && tooltip.name !== 'Popup Box') { + // Store in localStorage directly + const db = getGearDB(); + const match = db.find(e => e.id === idMatch[1]); + if (match) { + match.stats = tooltip.stats; + saveGearDB(db); + } + results.push(tooltip); + console.log(`%c[HV] [${idx}] ${tooltip.name}`, 'color:#888'); + } + idx++; + next(); + }, 300); + return; + } catch (e) {} + } + idx++; + next(); + } + + next(); + return 'Capturing tooltips... check console'; +} + // ── Auto-detect and scrape current page ── function autoScrapeGear() { const url = window.location.href || ''; @@ -3954,6 +3999,7 @@ window.HV = { gearSummary: () => logGearSummary(), scrapeGear: () => autoScrapeGear(), gearDebug: () => debugScrapeGear(), + captureTooltips: () => captureAllTooltips(), }; // ═══════════════════════════════════════════════════════════════════════ diff --git a/scripts/latest.user.js b/scripts/latest.user.js index a8ee740..d7da28f 100644 --- a/scripts/latest.user.js +++ b/scripts/latest.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name HV Unified // @namespace hvunified -// @version 0.14.11 +// @version 0.14.12 // @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse // @author GaboGG + Hermes // @match *://*.hentaiverse.org/* @@ -17,7 +17,7 @@ // CONFIG — default settings // ═══════════════════════════════════════════════════════════════════════ -const VERSION = '0.14.11'; +const VERSION = '0.14.12'; const CFG = { // — Battle automation @@ -3442,18 +3442,17 @@ function scrapeCharacterEquip() { }); // Read the popup box for the currently-displayed tooltip - const tooltip = parseTooltipPopup(); - - // Merge tooltip stats with the matching item - if (tooltip && tooltip.name) { - const matchIdx = scraped.findIndex(s => tooltip.name.includes(s.name) || s.name.includes(tooltip.name)); - if (matchIdx >= 0) { - scraped[matchIdx].stats = tooltip.stats; - } else if (scraped.length > 0) { - // If no match, attach to first item as extra info - scraped[0].tooltipStats = tooltip.stats; + // Note: popup_box only updates on actual hover; triggerAllTooltips + // may not work if equips.set is async. We still get names/IDs from slots. + try { + const tooltip = parseTooltipPopup(); + if (tooltip && tooltip.name && tooltip.name !== 'Popup Box') { + const matchIdx = scraped.findIndex(s => tooltip.name.includes(s.name) || s.name.includes(tooltip.name)); + if (matchIdx >= 0) { + scraped[matchIdx].stats = tooltip.stats; + } } - } + } catch (e) {} if (scraped.length > 0) { const db = getGearDB(); @@ -3563,20 +3562,66 @@ function triggerAllTooltips() { const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : slot.getAttribute('onmouseover') || ''; const idMatch = omo.match(/equips\.set\((\d+)/); if (idMatch && typeof equips !== 'undefined' && equips.set) { - // Trigger the tooltip - equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130); - - // Read the popup - const tooltip = parseTooltipPopup(); - if (tooltip && tooltip.name) { - results.push(tooltip); - } + try { + equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130); + } catch (e) {} } }); return results; } +// Manual: hover each item and capture tooltip stats with delays +// Run this from console on the character equipment page for full stats +function captureAllTooltips(delay = 400) { + const slots = document.querySelectorAll('#eqsb > .eqb'); + const results = []; + let idx = 0; + + function next() { + if (idx >= slots.length) { + console.log(`%c[HV] Captured ${results.length} tooltips`, 'color:#0f0'); + // Re-scrape with the captured data + autoScrapeGear(); + return; + } + + const slot = slots[idx]; + const nameDiv = slot.querySelector(':scope > div[onmouseover]'); + const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : ''; + const idMatch = omo.match(/equips\.set\((\d+)/); + + if (idMatch && typeof equips !== 'undefined' && equips.set) { + try { + equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130); + // Wait for popup to populate + setTimeout(() => { + const tooltip = parseTooltipPopup(); + if (tooltip && tooltip.name && tooltip.name !== 'Popup Box') { + // Store in localStorage directly + const db = getGearDB(); + const match = db.find(e => e.id === idMatch[1]); + if (match) { + match.stats = tooltip.stats; + saveGearDB(db); + } + results.push(tooltip); + console.log(`%c[HV] [${idx}] ${tooltip.name}`, 'color:#888'); + } + idx++; + next(); + }, 300); + return; + } catch (e) {} + } + idx++; + next(); + } + + next(); + return 'Capturing tooltips... check console'; +} + // ── Auto-detect and scrape current page ── function autoScrapeGear() { const url = window.location.href || ''; @@ -3954,6 +3999,7 @@ window.HV = { gearSummary: () => logGearSummary(), scrapeGear: () => autoScrapeGear(), gearDebug: () => debugScrapeGear(), + captureTooltips: () => captureAllTooltips(), }; // ═══════════════════════════════════════════════════════════════════════ diff --git a/src/config.js b/src/config.js index 2f8d48a..6b5a725 100644 --- a/src/config.js +++ b/src/config.js @@ -2,7 +2,7 @@ // CONFIG — default settings // ═══════════════════════════════════════════════════════════════════════ -const VERSION = '0.14.11'; +const VERSION = '0.14.12'; const CFG = { // — Battle automation diff --git a/src/gear-scraper.js b/src/gear-scraper.js index b1dc1ec..4638a4e 100644 --- a/src/gear-scraper.js +++ b/src/gear-scraper.js @@ -199,18 +199,17 @@ function scrapeCharacterEquip() { }); // Read the popup box for the currently-displayed tooltip - const tooltip = parseTooltipPopup(); - - // Merge tooltip stats with the matching item - if (tooltip && tooltip.name) { - const matchIdx = scraped.findIndex(s => tooltip.name.includes(s.name) || s.name.includes(tooltip.name)); - if (matchIdx >= 0) { - scraped[matchIdx].stats = tooltip.stats; - } else if (scraped.length > 0) { - // If no match, attach to first item as extra info - scraped[0].tooltipStats = tooltip.stats; + // Note: popup_box only updates on actual hover; triggerAllTooltips + // may not work if equips.set is async. We still get names/IDs from slots. + try { + const tooltip = parseTooltipPopup(); + if (tooltip && tooltip.name && tooltip.name !== 'Popup Box') { + const matchIdx = scraped.findIndex(s => tooltip.name.includes(s.name) || s.name.includes(tooltip.name)); + if (matchIdx >= 0) { + scraped[matchIdx].stats = tooltip.stats; + } } - } + } catch (e) {} if (scraped.length > 0) { const db = getGearDB(); @@ -320,20 +319,66 @@ function triggerAllTooltips() { const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : slot.getAttribute('onmouseover') || ''; const idMatch = omo.match(/equips\.set\((\d+)/); if (idMatch && typeof equips !== 'undefined' && equips.set) { - // Trigger the tooltip - equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130); - - // Read the popup - const tooltip = parseTooltipPopup(); - if (tooltip && tooltip.name) { - results.push(tooltip); - } + try { + equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130); + } catch (e) {} } }); return results; } +// Manual: hover each item and capture tooltip stats with delays +// Run this from console on the character equipment page for full stats +function captureAllTooltips(delay = 400) { + const slots = document.querySelectorAll('#eqsb > .eqb'); + const results = []; + let idx = 0; + + function next() { + if (idx >= slots.length) { + console.log(`%c[HV] Captured ${results.length} tooltips`, 'color:#0f0'); + // Re-scrape with the captured data + autoScrapeGear(); + return; + } + + const slot = slots[idx]; + const nameDiv = slot.querySelector(':scope > div[onmouseover]'); + const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : ''; + const idMatch = omo.match(/equips\.set\((\d+)/); + + if (idMatch && typeof equips !== 'undefined' && equips.set) { + try { + equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130); + // Wait for popup to populate + setTimeout(() => { + const tooltip = parseTooltipPopup(); + if (tooltip && tooltip.name && tooltip.name !== 'Popup Box') { + // Store in localStorage directly + const db = getGearDB(); + const match = db.find(e => e.id === idMatch[1]); + if (match) { + match.stats = tooltip.stats; + saveGearDB(db); + } + results.push(tooltip); + console.log(`%c[HV] [${idx}] ${tooltip.name}`, 'color:#888'); + } + idx++; + next(); + }, 300); + return; + } catch (e) {} + } + idx++; + next(); + } + + next(); + return 'Capturing tooltips... check console'; +} + // ── Auto-detect and scrape current page ── function autoScrapeGear() { const url = window.location.href || ''; diff --git a/src/header.user.js b/src/header.user.js index 6685206..0bc3eb6 100644 --- a/src/header.user.js +++ b/src/header.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name HV Unified // @namespace hvunified -// @version 0.14.11 +// @version 0.14.12 // @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse // @author GaboGG + Hermes // @match *://*.hentaiverse.org/* diff --git a/src/public-api.js b/src/public-api.js index fd99792..46fd81f 100644 --- a/src/public-api.js +++ b/src/public-api.js @@ -25,4 +25,5 @@ window.HV = { gearSummary: () => logGearSummary(), scrapeGear: () => autoScrapeGear(), gearDebug: () => debugScrapeGear(), + captureTooltips: () => captureAllTooltips(), };