REMOVED (owned by MB/HVUT): - RE timer (HVUtils has one) - Battle keybinds Q/H/C (Monsterbation owns battle keys; kept , for settings) - Hover-attack battle UI hooks (Monsterbation) - Battle logger (Monsterbation combat log) - Spirit/potion/scroll auto-use in battle (Monsterbation) - Armory bulk sell/salvage/shrine UI + Keep Top 10% button (HVUtils bulk tools) RESOLVED: - Q keybind collision: yielded to Monsterbation - DOM double-injection: removed duplicate overlays - Storage: hvunified_ namespace isolated from HVUT GM_* storage KEPT (gaps community doesn't cover): - Gear analysis/scoring (equipped vs store, 19-category advisory) - Strategy guidance as advisory layer (HV.advice/HV.action) - Guidance/abilities/difficulty advisor - window.HV public API bridge
111 lines
3.9 KiB
JavaScript
111 lines
3.9 KiB
JavaScript
// ═══════════════════════════════════════════════════════════════════════
|
|
// ACTION EXECUTOR — carry out recommended actions
|
|
// ═══════════════════════════════════════════════════════════════════════
|
|
|
|
function executeAction(a) {
|
|
if (!a) return false;
|
|
let result = false;
|
|
switch (a.type) {
|
|
case 'attack': result = attackMonster(a.target); break;
|
|
case 'spell': result = a.selfTarget ? castSelfSpell(a.name) : castTargetSpell(a.name, a.target); break;
|
|
case 'skill': result = useSkill(a.name, a.target); break;
|
|
case 'item': result = useItem(a.id); break;
|
|
}
|
|
if (result) {
|
|
STATE._lastActionTime = Date.now();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
function attackMonster(i) {
|
|
if (i < 0 || i >= STATE.monsters.length) return false;
|
|
const m = STATE.monsters[i];
|
|
if (!m || !m.hasAttribute || !m.hasAttribute('onclick')) return false;
|
|
m.click();
|
|
return true;
|
|
}
|
|
|
|
function castSelfSpell(n) {
|
|
const s = $$('.btsd[onclick]').find(el =>
|
|
(el.getAttribute('onmouseover') || '').includes(`set_infopane_spell('${n}'`));
|
|
if (!s) return false;
|
|
s.click();
|
|
return true;
|
|
}
|
|
|
|
function castTargetSpell(n, i) {
|
|
const s = $$('.btsd[onclick]').find(el =>
|
|
(el.getAttribute('onmouseover') || '').includes(`set_infopane_spell('${n}'`));
|
|
if (!s) return false;
|
|
s.click();
|
|
// Target selection: click immediately, no setTimeout delay needed.
|
|
// HV's native lock_action handles the state transition synchronously.
|
|
if (i >= 0 && i < STATE.monsters.length) {
|
|
const m = STATE.monsters[i];
|
|
if (m && m.hasAttribute && m.hasAttribute('onclick')) m.click();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function useItem(id) {
|
|
let it = document.getElementById('ikey_' + id);
|
|
|
|
// Fallback for auto_ slot IDs (on-cooldown items without explicit DOM id):
|
|
// search for element with matching onmouseover item ID
|
|
if (!it && typeof id === 'string' && id.startsWith('auto_')) {
|
|
const rawId = id.replace('auto_', '');
|
|
const itemPane = document.getElementById('pane_item');
|
|
if (itemPane) {
|
|
it = $$('div[onmouseover*="set_infopane_item(' + rawId + ')"]', itemPane)[0];
|
|
}
|
|
}
|
|
|
|
if (!it) return false;
|
|
// Track that we used the P-slot gem so we don't retry stale state
|
|
if (id === 'p') STATE._mysticUsed = true;
|
|
dummy.setAttribute('onclick', it.getAttribute('onmouseover'));
|
|
dummy.click();
|
|
it.click();
|
|
return true;
|
|
}
|
|
|
|
function useSkill(n, i) {
|
|
let el = null;
|
|
|
|
// Try quickbar first
|
|
for (const e of $$('#quickbar > .btqs[onclick]')) {
|
|
if ((e.getAttribute('onmouseover') || '').includes(`set_infopane_spell('${n}'`)) {
|
|
el = e; break;
|
|
}
|
|
}
|
|
// Try spellbook
|
|
if (!el) {
|
|
el = $$('.btsd[onclick]').find(e =>
|
|
(e.getAttribute('onmouseover') || '').includes(`set_infopane_spell('${n}'`));
|
|
}
|
|
// Fallback: onclick match
|
|
if (!el) {
|
|
for (const e of $$('.btqb[onclick]')) {
|
|
if ((e.getAttribute('onclick') || '').includes(n)) { el = e; break; }
|
|
}
|
|
}
|
|
// Fallback: image match
|
|
if (!el) {
|
|
for (const e of $$('.btqb img')) {
|
|
if ((e.src || '').toLowerCase().includes(n.toLowerCase().replace(/\s+/g, '_'))) {
|
|
el = e.parentElement; break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!el) return false;
|
|
el.click();
|
|
// Click target immediately — no setTimeout needed
|
|
if (i >= 0 && i < STATE.monsters.length) {
|
|
const m = STATE.monsters[i];
|
|
if (m && m.hasAttribute && m.hasAttribute('onclick')) m.click();
|
|
}
|
|
return true;
|
|
}
|
|
|