diff --git a/scripts/hv-unified.user.js b/scripts/hv-unified.user.js index bb8c6a7..33d730c 100644 --- a/scripts/hv-unified.user.js +++ b/scripts/hv-unified.user.js @@ -868,10 +868,24 @@ function strategyNovice() { const gem = hasUsableGem('mana'); if (gem) return { type: 'item', id: gem.id, selfTarget: true }; } - // Spirit gem — use whenever we have one, regardless of SP - // Keeps SP topped for Spirit Stance and Spark of Life (50% cost) - const spiritItem = hasUsableGem('spirit'); - if (spiritItem) return { type: 'item', id: spiritItem.id, selfTarget: true }; + // Spirit gem (P-slot) — use immediately when available (free to refill) + const pGem = document.getElementById('ikey_p'); + const pGemId = pGem ? (pGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null; + if (pGemId && pGemId[1] === '10007') { + // P-slot has a Spirit Gem (10007) — use it + if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true }; + } + // Spirit draughts/potions — only when SP drops below threshold + if (STATE.sp < CFG.spiritPotionSP) { + // Check non-P-slot spirit items only + for (const [slot, info] of Object.entries(STATE.itemsKnown)) { + if (slot === 'p') continue; + const def = ITEMS[parseInt(info)]; + if (def && def.t === 'spirit') { + return { type: 'item', id: slot, selfTarget: true }; + } + } + } // 5. Spirit Stance at OC 60 — but only if we have SP to sustain it if (STATE.oc >= 60 && !STATE.spiritStance && STATE.sp > 0.10) @@ -977,9 +991,20 @@ function strategyAdept() { const gem = hasUsableGem('mana'); if (gem) return { type: 'item', id: gem.id, selfTarget: true }; } - // Spirit gem — use whenever available (tops SP for Spark + Stance) - const aspiritItem = hasUsableGem('spirit'); - if (aspiritItem) return { type: 'item', id: aspiritItem.id, selfTarget: true }; + // Spirit gem (P-slot) — use immediately + const apGem = document.getElementById('ikey_p'); + const apGemId = apGem ? (apGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null; + if (apGemId && apGemId[1] === '10007') { + if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true }; + } + // Spirit draughts/potions — only at SP < threshold + if (STATE.sp < CFG.spiritPotionSP) { + for (const [slot, info] of Object.entries(STATE.itemsKnown)) { + if (slot === 'p') continue; + const def = ITEMS[parseInt(info)]; + if (def && def.t === 'spirit') return { type: 'item', id: slot, selfTarget: true }; + } + } // 4. Debuffs — only on important fights (rare/boss/ultimate monsters) // In random mob fights, just attack through them @@ -1102,9 +1127,20 @@ function strategyVeteran() { const gem = hasUsableGem('mana'); if (gem) return { type: 'item', id: gem.id, selfTarget: true }; } - // Spirit gem — use whenever available - const vspiritItem = hasUsableGem('spirit'); - if (vspiritItem) return { type: 'item', id: vspiritItem.id, selfTarget: true }; + // Spirit gem (P-slot) — use immediately + const vpGem = document.getElementById('ikey_p'); + const vpGemId = vpGem ? (vpGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null; + if (vpGemId && vpGemId[1] === '10007') { + if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true }; + } + // Spirit draughts/potions — only at SP < threshold + if (STATE.sp < CFG.spiritPotionSP) { + for (const [slot, info] of Object.entries(STATE.itemsKnown)) { + if (slot === 'p') continue; + const def = ITEMS[parseInt(info)]; + if (def && def.t === 'spirit') return { type: 'item', id: slot, selfTarget: true }; + } + } // 4. Debuffs — only on important fights (rare/boss) if (CFG.autoDebuff && STATE.mp > 0.2 && (anyRareMonster() || STATE.monsters.length <= 2)) { diff --git a/scripts/latest.user.js b/scripts/latest.user.js index bb8c6a7..33d730c 100644 --- a/scripts/latest.user.js +++ b/scripts/latest.user.js @@ -868,10 +868,24 @@ function strategyNovice() { const gem = hasUsableGem('mana'); if (gem) return { type: 'item', id: gem.id, selfTarget: true }; } - // Spirit gem — use whenever we have one, regardless of SP - // Keeps SP topped for Spirit Stance and Spark of Life (50% cost) - const spiritItem = hasUsableGem('spirit'); - if (spiritItem) return { type: 'item', id: spiritItem.id, selfTarget: true }; + // Spirit gem (P-slot) — use immediately when available (free to refill) + const pGem = document.getElementById('ikey_p'); + const pGemId = pGem ? (pGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null; + if (pGemId && pGemId[1] === '10007') { + // P-slot has a Spirit Gem (10007) — use it + if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true }; + } + // Spirit draughts/potions — only when SP drops below threshold + if (STATE.sp < CFG.spiritPotionSP) { + // Check non-P-slot spirit items only + for (const [slot, info] of Object.entries(STATE.itemsKnown)) { + if (slot === 'p') continue; + const def = ITEMS[parseInt(info)]; + if (def && def.t === 'spirit') { + return { type: 'item', id: slot, selfTarget: true }; + } + } + } // 5. Spirit Stance at OC 60 — but only if we have SP to sustain it if (STATE.oc >= 60 && !STATE.spiritStance && STATE.sp > 0.10) @@ -977,9 +991,20 @@ function strategyAdept() { const gem = hasUsableGem('mana'); if (gem) return { type: 'item', id: gem.id, selfTarget: true }; } - // Spirit gem — use whenever available (tops SP for Spark + Stance) - const aspiritItem = hasUsableGem('spirit'); - if (aspiritItem) return { type: 'item', id: aspiritItem.id, selfTarget: true }; + // Spirit gem (P-slot) — use immediately + const apGem = document.getElementById('ikey_p'); + const apGemId = apGem ? (apGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null; + if (apGemId && apGemId[1] === '10007') { + if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true }; + } + // Spirit draughts/potions — only at SP < threshold + if (STATE.sp < CFG.spiritPotionSP) { + for (const [slot, info] of Object.entries(STATE.itemsKnown)) { + if (slot === 'p') continue; + const def = ITEMS[parseInt(info)]; + if (def && def.t === 'spirit') return { type: 'item', id: slot, selfTarget: true }; + } + } // 4. Debuffs — only on important fights (rare/boss/ultimate monsters) // In random mob fights, just attack through them @@ -1102,9 +1127,20 @@ function strategyVeteran() { const gem = hasUsableGem('mana'); if (gem) return { type: 'item', id: gem.id, selfTarget: true }; } - // Spirit gem — use whenever available - const vspiritItem = hasUsableGem('spirit'); - if (vspiritItem) return { type: 'item', id: vspiritItem.id, selfTarget: true }; + // Spirit gem (P-slot) — use immediately + const vpGem = document.getElementById('ikey_p'); + const vpGemId = vpGem ? (vpGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null; + if (vpGemId && vpGemId[1] === '10007') { + if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true }; + } + // Spirit draughts/potions — only at SP < threshold + if (STATE.sp < CFG.spiritPotionSP) { + for (const [slot, info] of Object.entries(STATE.itemsKnown)) { + if (slot === 'p') continue; + const def = ITEMS[parseInt(info)]; + if (def && def.t === 'spirit') return { type: 'item', id: slot, selfTarget: true }; + } + } // 4. Debuffs — only on important fights (rare/boss) if (CFG.autoDebuff && STATE.mp > 0.2 && (anyRareMonster() || STATE.monsters.length <= 2)) { diff --git a/src/strategy-engine.js b/src/strategy-engine.js index 5213643..4afde98 100644 --- a/src/strategy-engine.js +++ b/src/strategy-engine.js @@ -223,10 +223,24 @@ function strategyNovice() { const gem = hasUsableGem('mana'); if (gem) return { type: 'item', id: gem.id, selfTarget: true }; } - // Spirit gem — use whenever we have one, regardless of SP - // Keeps SP topped for Spirit Stance and Spark of Life (50% cost) - const spiritItem = hasUsableGem('spirit'); - if (spiritItem) return { type: 'item', id: spiritItem.id, selfTarget: true }; + // Spirit gem (P-slot) — use immediately when available (free to refill) + const pGem = document.getElementById('ikey_p'); + const pGemId = pGem ? (pGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null; + if (pGemId && pGemId[1] === '10007') { + // P-slot has a Spirit Gem (10007) — use it + if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true }; + } + // Spirit draughts/potions — only when SP drops below threshold + if (STATE.sp < CFG.spiritPotionSP) { + // Check non-P-slot spirit items only + for (const [slot, info] of Object.entries(STATE.itemsKnown)) { + if (slot === 'p') continue; + const def = ITEMS[parseInt(info)]; + if (def && def.t === 'spirit') { + return { type: 'item', id: slot, selfTarget: true }; + } + } + } // 5. Spirit Stance at OC 60 — but only if we have SP to sustain it if (STATE.oc >= 60 && !STATE.spiritStance && STATE.sp > 0.10) @@ -332,9 +346,20 @@ function strategyAdept() { const gem = hasUsableGem('mana'); if (gem) return { type: 'item', id: gem.id, selfTarget: true }; } - // Spirit gem — use whenever available (tops SP for Spark + Stance) - const aspiritItem = hasUsableGem('spirit'); - if (aspiritItem) return { type: 'item', id: aspiritItem.id, selfTarget: true }; + // Spirit gem (P-slot) — use immediately + const apGem = document.getElementById('ikey_p'); + const apGemId = apGem ? (apGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null; + if (apGemId && apGemId[1] === '10007') { + if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true }; + } + // Spirit draughts/potions — only at SP < threshold + if (STATE.sp < CFG.spiritPotionSP) { + for (const [slot, info] of Object.entries(STATE.itemsKnown)) { + if (slot === 'p') continue; + const def = ITEMS[parseInt(info)]; + if (def && def.t === 'spirit') return { type: 'item', id: slot, selfTarget: true }; + } + } // 4. Debuffs — only on important fights (rare/boss/ultimate monsters) // In random mob fights, just attack through them @@ -457,9 +482,20 @@ function strategyVeteran() { const gem = hasUsableGem('mana'); if (gem) return { type: 'item', id: gem.id, selfTarget: true }; } - // Spirit gem — use whenever available - const vspiritItem = hasUsableGem('spirit'); - if (vspiritItem) return { type: 'item', id: vspiritItem.id, selfTarget: true }; + // Spirit gem (P-slot) — use immediately + const vpGem = document.getElementById('ikey_p'); + const vpGemId = vpGem ? (vpGem.getAttribute('onmouseover') || '').match(/set_infopane_item\((\d+)\)/) : null; + if (vpGemId && vpGemId[1] === '10007') { + if (hasUsableGem('spirit')) return { type: 'item', id: 'p', selfTarget: true }; + } + // Spirit draughts/potions — only at SP < threshold + if (STATE.sp < CFG.spiritPotionSP) { + for (const [slot, info] of Object.entries(STATE.itemsKnown)) { + if (slot === 'p') continue; + const def = ITEMS[parseInt(info)]; + if (def && def.t === 'spirit') return { type: 'item', id: slot, selfTarget: true }; + } + } // 4. Debuffs — only on important fights (rare/boss) if (CFG.autoDebuff && STATE.mp > 0.2 && (anyRareMonster() || STATE.monsters.length <= 2)) {