From 4bc90d9332e498b375a31dfcd3ae49c55c850bbc Mon Sep 17 00:00:00 2001 From: GaboGG Date: Mon, 20 Jul 2026 20:35:14 -0400 Subject: [PATCH] Monster Lab floating panel + page detection, Beast recommendation - Monster Lab page detected via ss=ml - Floating draggable panel replaces inline UI (was messing layout) - Feed All + Happy Pills All buttons - Class recommendation for first monster - Drag-to-move via header grab --- scripts/hv-unified.user.js | 113 +++++++++++++++++++++++++++++-------- scripts/latest.user.js | 113 +++++++++++++++++++++++++++++-------- src/init.js | 1 + src/out-of-battle.js | 111 ++++++++++++++++++++++++++++-------- src/page-detector.js | 1 + 5 files changed, 267 insertions(+), 72 deletions(-) diff --git a/scripts/hv-unified.user.js b/scripts/hv-unified.user.js index 3104c1a..fa5050e 100644 --- a/scripts/hv-unified.user.js +++ b/scripts/hv-unified.user.js @@ -269,6 +269,7 @@ function detectPage() { 'ss=rf': 'reforge', 'ss=sf': 'soulfuse', 'ss=ab': 'abilities', + 'ss=ml': 'monster', 'ss=it': 'invitems', 'ss=se': 'settings', 'ss=ss': 'spiritshop', @@ -1805,38 +1806,101 @@ function enhanceTraining() { if (ta) ta.insertBefore(d, ta.firstChild); } -// ── Monster Lab: feed all ── +// ── Monster Lab: floating info panel + feed buttons ── + +let _mlDragOffset = { x: 0, y: 0 }; function enhanceMonsterLab() { - const m = document.getElementById('mainpane'); - if (!m || document.getElementById('hv-lab-enhance')) return; + // Create floating draggable panel + if (document.getElementById('hv-monster')) return; - const r = document.createElement('div'); - r.id = 'hv-lab-enhance'; - r.style.cssText = 'margin:8px;padding:8px;display:flex;gap:8px'; + const panel = document.createElement('div'); + panel.id = 'hv-monster'; + panel.style.cssText = css({ + position: 'fixed', + top: '80px', + right: '4px', + zIndex: '9999', + background: '#111827', + color: '#d1d5db', + padding: '8px 10px', + borderRadius: '8px', + fontSize: '10px', + fontFamily: 'monospace', + maxWidth: '320px', + boxShadow: '0 0 15px rgba(0,0,0,0.6)', + border: '1px solid #374151', + cursor: 'move', + userSelect: 'none', + }); - const f = document.createElement('input'); - f.type = 'button'; - f.value = '🍖 Feed All'; - f.style.cssText = 'padding:4px 10px;cursor:pointer;background:#2a5a2a;color:#fff;border:none;border-radius:3px;font-size:11px'; - f.onclick = () => { $$('input[value="Feed"]', m).forEach(b => b.click()); }; + const body = `
+ 🧬 Monster Lab + +
+
+
+ + +
+
+ New to ML? Pick a Beast-class (Dog/Cow/Pig) for STR/END crystals.
+ Click + drag header to move. +
+
`; - const p = document.createElement('input'); - p.type = 'button'; - p.value = '💊 Happy Pills All'; - p.style.cssText = 'padding:4px 10px;cursor:pointer;background:#5a3a2a;color:#fff;border:none;border-radius:3px;font-size:11px'; - p.onclick = () => { - const pills = $$('option', m).filter(o => (o.textContent || '').includes('Happy Pill')); - if (pills.length > 0) { - pills[0].selected = true; - $$('input[value="Feed"]', m).forEach(b => b.click()); + panel.innerHTML = body; + document.body.appendChild(panel); + + // ── Feed All ── + panel.querySelector('#hv-feed-all').onclick = () => { + const m = document.getElementById('mainpane'); + if (m) $$('input[value="Feed"]', m).forEach(b => b.click()); + }; + + // ── Happy Pills All ── + panel.querySelector('#hv-pill-all').onclick = () => { + const m = document.getElementById('mainpane'); + if (m) { + const pills = $$('option', m).filter(o => (o.textContent || '').includes('Happy Pill')); + if (pills.length > 0) { + pills[0].selected = true; + $$('input[value="Feed"]', m).forEach(b => b.click()); + } } }; - r.appendChild(f); - r.appendChild(p); - const ta = m.querySelector('div'); - if (ta) ta.insertBefore(r, ta.firstChild); + // ── Toggle ── + panel.querySelector('#hv-monster-toggle').onclick = () => { + const body = panel.querySelector('#hv-monster-body'); + const isHidden = body.style.display === 'none'; + body.style.display = isHidden ? 'block' : 'none'; + panel.querySelector('#hv-monster-toggle').textContent = isHidden ? '−' : '+'; + }; + + // ── Make draggable ── + const header = panel.querySelector('#hv-monster-header'); + if (header) { + header.addEventListener('mousedown', (e) => { + _mlDragOffset.x = e.clientX - panel.getBoundingClientRect().left; + _mlDragOffset.y = e.clientY - panel.getBoundingClientRect().top; + const onMove = (ev) => { + panel.style.left = (ev.clientX - _mlDragOffset.x) + 'px'; + panel.style.right = 'auto'; + panel.style.top = (ev.clientY - _mlDragOffset.y) + 'px'; + }; + const onUp = () => { + document.removeEventListener('mousemove', onMove); + document.removeEventListener('mouseup', onUp); + }; + document.addEventListener('mousemove', onMove); + document.addEventListener('mouseup', onUp); + }); + } + + // Remove the old inline bar if it exists + const oldBar = document.getElementById('hv-lab-enhance'); + if (oldBar) oldBar.remove(); } // ── Config button (bottom-right) ── @@ -2803,6 +2867,7 @@ function init() { if (STATE.page === 'character') showGuidancePanel(); if (STATE.page === 'armory') enhanceArmory(); if (STATE.page === 'abilities') enhanceAbilities(); + if (STATE.page === 'monster') enhanceMonsterLab(); } // Dawn initialization diff --git a/scripts/latest.user.js b/scripts/latest.user.js index 3104c1a..fa5050e 100644 --- a/scripts/latest.user.js +++ b/scripts/latest.user.js @@ -269,6 +269,7 @@ function detectPage() { 'ss=rf': 'reforge', 'ss=sf': 'soulfuse', 'ss=ab': 'abilities', + 'ss=ml': 'monster', 'ss=it': 'invitems', 'ss=se': 'settings', 'ss=ss': 'spiritshop', @@ -1805,38 +1806,101 @@ function enhanceTraining() { if (ta) ta.insertBefore(d, ta.firstChild); } -// ── Monster Lab: feed all ── +// ── Monster Lab: floating info panel + feed buttons ── + +let _mlDragOffset = { x: 0, y: 0 }; function enhanceMonsterLab() { - const m = document.getElementById('mainpane'); - if (!m || document.getElementById('hv-lab-enhance')) return; + // Create floating draggable panel + if (document.getElementById('hv-monster')) return; - const r = document.createElement('div'); - r.id = 'hv-lab-enhance'; - r.style.cssText = 'margin:8px;padding:8px;display:flex;gap:8px'; + const panel = document.createElement('div'); + panel.id = 'hv-monster'; + panel.style.cssText = css({ + position: 'fixed', + top: '80px', + right: '4px', + zIndex: '9999', + background: '#111827', + color: '#d1d5db', + padding: '8px 10px', + borderRadius: '8px', + fontSize: '10px', + fontFamily: 'monospace', + maxWidth: '320px', + boxShadow: '0 0 15px rgba(0,0,0,0.6)', + border: '1px solid #374151', + cursor: 'move', + userSelect: 'none', + }); - const f = document.createElement('input'); - f.type = 'button'; - f.value = '🍖 Feed All'; - f.style.cssText = 'padding:4px 10px;cursor:pointer;background:#2a5a2a;color:#fff;border:none;border-radius:3px;font-size:11px'; - f.onclick = () => { $$('input[value="Feed"]', m).forEach(b => b.click()); }; + const body = `
+ 🧬 Monster Lab + +
+
+
+ + +
+
+ New to ML? Pick a Beast-class (Dog/Cow/Pig) for STR/END crystals.
+ Click + drag header to move. +
+
`; - const p = document.createElement('input'); - p.type = 'button'; - p.value = '💊 Happy Pills All'; - p.style.cssText = 'padding:4px 10px;cursor:pointer;background:#5a3a2a;color:#fff;border:none;border-radius:3px;font-size:11px'; - p.onclick = () => { - const pills = $$('option', m).filter(o => (o.textContent || '').includes('Happy Pill')); - if (pills.length > 0) { - pills[0].selected = true; - $$('input[value="Feed"]', m).forEach(b => b.click()); + panel.innerHTML = body; + document.body.appendChild(panel); + + // ── Feed All ── + panel.querySelector('#hv-feed-all').onclick = () => { + const m = document.getElementById('mainpane'); + if (m) $$('input[value="Feed"]', m).forEach(b => b.click()); + }; + + // ── Happy Pills All ── + panel.querySelector('#hv-pill-all').onclick = () => { + const m = document.getElementById('mainpane'); + if (m) { + const pills = $$('option', m).filter(o => (o.textContent || '').includes('Happy Pill')); + if (pills.length > 0) { + pills[0].selected = true; + $$('input[value="Feed"]', m).forEach(b => b.click()); + } } }; - r.appendChild(f); - r.appendChild(p); - const ta = m.querySelector('div'); - if (ta) ta.insertBefore(r, ta.firstChild); + // ── Toggle ── + panel.querySelector('#hv-monster-toggle').onclick = () => { + const body = panel.querySelector('#hv-monster-body'); + const isHidden = body.style.display === 'none'; + body.style.display = isHidden ? 'block' : 'none'; + panel.querySelector('#hv-monster-toggle').textContent = isHidden ? '−' : '+'; + }; + + // ── Make draggable ── + const header = panel.querySelector('#hv-monster-header'); + if (header) { + header.addEventListener('mousedown', (e) => { + _mlDragOffset.x = e.clientX - panel.getBoundingClientRect().left; + _mlDragOffset.y = e.clientY - panel.getBoundingClientRect().top; + const onMove = (ev) => { + panel.style.left = (ev.clientX - _mlDragOffset.x) + 'px'; + panel.style.right = 'auto'; + panel.style.top = (ev.clientY - _mlDragOffset.y) + 'px'; + }; + const onUp = () => { + document.removeEventListener('mousemove', onMove); + document.removeEventListener('mouseup', onUp); + }; + document.addEventListener('mousemove', onMove); + document.addEventListener('mouseup', onUp); + }); + } + + // Remove the old inline bar if it exists + const oldBar = document.getElementById('hv-lab-enhance'); + if (oldBar) oldBar.remove(); } // ── Config button (bottom-right) ── @@ -2803,6 +2867,7 @@ function init() { if (STATE.page === 'character') showGuidancePanel(); if (STATE.page === 'armory') enhanceArmory(); if (STATE.page === 'abilities') enhanceAbilities(); + if (STATE.page === 'monster') enhanceMonsterLab(); } // Dawn initialization diff --git a/src/init.js b/src/init.js index fa9fa93..793bd2e 100644 --- a/src/init.js +++ b/src/init.js @@ -26,6 +26,7 @@ function init() { if (STATE.page === 'character') showGuidancePanel(); if (STATE.page === 'armory') enhanceArmory(); if (STATE.page === 'abilities') enhanceAbilities(); + if (STATE.page === 'monster') enhanceMonsterLab(); } // Dawn initialization diff --git a/src/out-of-battle.js b/src/out-of-battle.js index 8020e90..a849e78 100644 --- a/src/out-of-battle.js +++ b/src/out-of-battle.js @@ -228,38 +228,101 @@ function enhanceTraining() { if (ta) ta.insertBefore(d, ta.firstChild); } -// ── Monster Lab: feed all ── +// ── Monster Lab: floating info panel + feed buttons ── + +let _mlDragOffset = { x: 0, y: 0 }; function enhanceMonsterLab() { - const m = document.getElementById('mainpane'); - if (!m || document.getElementById('hv-lab-enhance')) return; + // Create floating draggable panel + if (document.getElementById('hv-monster')) return; - const r = document.createElement('div'); - r.id = 'hv-lab-enhance'; - r.style.cssText = 'margin:8px;padding:8px;display:flex;gap:8px'; + const panel = document.createElement('div'); + panel.id = 'hv-monster'; + panel.style.cssText = css({ + position: 'fixed', + top: '80px', + right: '4px', + zIndex: '9999', + background: '#111827', + color: '#d1d5db', + padding: '8px 10px', + borderRadius: '8px', + fontSize: '10px', + fontFamily: 'monospace', + maxWidth: '320px', + boxShadow: '0 0 15px rgba(0,0,0,0.6)', + border: '1px solid #374151', + cursor: 'move', + userSelect: 'none', + }); - const f = document.createElement('input'); - f.type = 'button'; - f.value = '🍖 Feed All'; - f.style.cssText = 'padding:4px 10px;cursor:pointer;background:#2a5a2a;color:#fff;border:none;border-radius:3px;font-size:11px'; - f.onclick = () => { $$('input[value="Feed"]', m).forEach(b => b.click()); }; + const body = `
+ 🧬 Monster Lab + +
+
+
+ + +
+
+ New to ML? Pick a Beast-class (Dog/Cow/Pig) for STR/END crystals.
+ Click + drag header to move. +
+
`; - const p = document.createElement('input'); - p.type = 'button'; - p.value = '💊 Happy Pills All'; - p.style.cssText = 'padding:4px 10px;cursor:pointer;background:#5a3a2a;color:#fff;border:none;border-radius:3px;font-size:11px'; - p.onclick = () => { - const pills = $$('option', m).filter(o => (o.textContent || '').includes('Happy Pill')); - if (pills.length > 0) { - pills[0].selected = true; - $$('input[value="Feed"]', m).forEach(b => b.click()); + panel.innerHTML = body; + document.body.appendChild(panel); + + // ── Feed All ── + panel.querySelector('#hv-feed-all').onclick = () => { + const m = document.getElementById('mainpane'); + if (m) $$('input[value="Feed"]', m).forEach(b => b.click()); + }; + + // ── Happy Pills All ── + panel.querySelector('#hv-pill-all').onclick = () => { + const m = document.getElementById('mainpane'); + if (m) { + const pills = $$('option', m).filter(o => (o.textContent || '').includes('Happy Pill')); + if (pills.length > 0) { + pills[0].selected = true; + $$('input[value="Feed"]', m).forEach(b => b.click()); + } } }; - r.appendChild(f); - r.appendChild(p); - const ta = m.querySelector('div'); - if (ta) ta.insertBefore(r, ta.firstChild); + // ── Toggle ── + panel.querySelector('#hv-monster-toggle').onclick = () => { + const body = panel.querySelector('#hv-monster-body'); + const isHidden = body.style.display === 'none'; + body.style.display = isHidden ? 'block' : 'none'; + panel.querySelector('#hv-monster-toggle').textContent = isHidden ? '−' : '+'; + }; + + // ── Make draggable ── + const header = panel.querySelector('#hv-monster-header'); + if (header) { + header.addEventListener('mousedown', (e) => { + _mlDragOffset.x = e.clientX - panel.getBoundingClientRect().left; + _mlDragOffset.y = e.clientY - panel.getBoundingClientRect().top; + const onMove = (ev) => { + panel.style.left = (ev.clientX - _mlDragOffset.x) + 'px'; + panel.style.right = 'auto'; + panel.style.top = (ev.clientY - _mlDragOffset.y) + 'px'; + }; + const onUp = () => { + document.removeEventListener('mousemove', onMove); + document.removeEventListener('mouseup', onUp); + }; + document.addEventListener('mousemove', onMove); + document.addEventListener('mouseup', onUp); + }); + } + + // Remove the old inline bar if it exists + const oldBar = document.getElementById('hv-lab-enhance'); + if (oldBar) oldBar.remove(); } // ── Config button (bottom-right) ── diff --git a/src/page-detector.js b/src/page-detector.js index b1c2458..5081c1e 100644 --- a/src/page-detector.js +++ b/src/page-detector.js @@ -33,6 +33,7 @@ function detectPage() { 'ss=rf': 'reforge', 'ss=sf': 'soulfuse', 'ss=ab': 'abilities', + 'ss=ml': 'monster', 'ss=it': 'invitems', 'ss=se': 'settings', 'ss=ss': 'spiritshop',