diff --git a/scripts/hv-unified.user.js b/scripts/hv-unified.user.js index 603f52c..f65b57c 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.3 +// @version 0.14.4 // @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.3'; +const VERSION = '0.14.4'; const CFG = { // — Battle automation @@ -1155,12 +1155,19 @@ function strategyNovice() { const ch = findBestChannelingTarget(); if (ch) return ch; } + // Collect available buff candidates and sort by cost + const buffCandidates = []; for (const b of BUFF_PRIORITY) { if (shouldBuff(b.icon, b.minTurns) && STATE.mp > 0.10 && hasReadySpell(b.spell)) { if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue; - return { type: 'spell', name: b.spell, selfTarget: true }; + const sp = findSpell(b.spell); + buffCandidates.push({ ...b, mpCost: sp ? sp.mp : 0 }); } } + if (buffCandidates.length > 0) { + buffCandidates.sort((a, b) => STATE.channeling ? b.mpCost - a.mpCost : a.mpCost - b.mpCost); + return { type: 'spell', name: buffCandidates[0].spell, selfTarget: true, _reason: STATE.channeling ? 'chBuff' : 'buff' }; + } // 4. Mana/spirit items — AFTER buffs (Novice) if (STATE.mp < CFG.manaGemMP) { @@ -1291,17 +1298,24 @@ function strategyAdept() { } // If channeling is active, prioritize most expensive buff for best value // Note: channeling reduces cost to ~1, but the game pre-checks base MP, - // so we skip spells we can't afford at base cost + // If channeling is active, prioritize most expensive buff for best value if (STATE.channeling && STATE.mp > 0.10) { const ch = findBestChannelingTarget(); if (ch) return ch; } + // Collect available buff candidates and sort by cost + const buffCandidates = []; for (const b of BUFF_PRIORITY) { if (shouldBuff(b.icon, b.minTurns) && STATE.mp > 0.10 && hasReadySpell(b.spell)) { if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue; - return { type: 'spell', name: b.spell, selfTarget: true }; + const sp = findSpell(b.spell); + buffCandidates.push({ ...b, mpCost: sp ? sp.mp : 0 }); } } + if (buffCandidates.length > 0) { + buffCandidates.sort((a, b) => STATE.channeling ? b.mpCost - a.mpCost : a.mpCost - b.mpCost); + return { type: 'spell', name: buffCandidates[0].spell, selfTarget: true, _reason: STATE.channeling ? 'chBuff' : 'buff' }; + } // 4. Mana/spirit items — AFTER buffs (Adept) if (STATE.mp < CFG.manaGemMP) { @@ -1447,12 +1461,20 @@ function strategyVeteran() { const ch = findBestChannelingTarget(); if (ch) return ch; } + // Collect available buff candidates and sort by cost + // No channeling → cheapest first (proc chance), channeling → most expensive (MP value) + const buffCandidates = []; for (const b of BUFF_PRIORITY) { if (shouldBuff(b.icon, b.minTurns) && STATE.mp > 0.10 && hasReadySpell(b.spell)) { if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue; - return { type: 'spell', name: b.spell, selfTarget: true, _reason: 'buff' }; + const sp = findSpell(b.spell); + buffCandidates.push({ ...b, mpCost: sp ? sp.mp : 0 }); } } + if (buffCandidates.length > 0) { + buffCandidates.sort((a, b) => STATE.channeling ? b.mpCost - a.mpCost : a.mpCost - b.mpCost); + return { type: 'spell', name: buffCandidates[0].spell, selfTarget: true, _reason: STATE.channeling ? 'chBuff' : 'buff' }; + } } // 4. Mana/spirit items — AFTER buffs (Novice) diff --git a/scripts/latest.user.js b/scripts/latest.user.js index 603f52c..f65b57c 100644 --- a/scripts/latest.user.js +++ b/scripts/latest.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name HV Unified // @namespace hvunified -// @version 0.14.3 +// @version 0.14.4 // @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.3'; +const VERSION = '0.14.4'; const CFG = { // — Battle automation @@ -1155,12 +1155,19 @@ function strategyNovice() { const ch = findBestChannelingTarget(); if (ch) return ch; } + // Collect available buff candidates and sort by cost + const buffCandidates = []; for (const b of BUFF_PRIORITY) { if (shouldBuff(b.icon, b.minTurns) && STATE.mp > 0.10 && hasReadySpell(b.spell)) { if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue; - return { type: 'spell', name: b.spell, selfTarget: true }; + const sp = findSpell(b.spell); + buffCandidates.push({ ...b, mpCost: sp ? sp.mp : 0 }); } } + if (buffCandidates.length > 0) { + buffCandidates.sort((a, b) => STATE.channeling ? b.mpCost - a.mpCost : a.mpCost - b.mpCost); + return { type: 'spell', name: buffCandidates[0].spell, selfTarget: true, _reason: STATE.channeling ? 'chBuff' : 'buff' }; + } // 4. Mana/spirit items — AFTER buffs (Novice) if (STATE.mp < CFG.manaGemMP) { @@ -1291,17 +1298,24 @@ function strategyAdept() { } // If channeling is active, prioritize most expensive buff for best value // Note: channeling reduces cost to ~1, but the game pre-checks base MP, - // so we skip spells we can't afford at base cost + // If channeling is active, prioritize most expensive buff for best value if (STATE.channeling && STATE.mp > 0.10) { const ch = findBestChannelingTarget(); if (ch) return ch; } + // Collect available buff candidates and sort by cost + const buffCandidates = []; for (const b of BUFF_PRIORITY) { if (shouldBuff(b.icon, b.minTurns) && STATE.mp > 0.10 && hasReadySpell(b.spell)) { if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue; - return { type: 'spell', name: b.spell, selfTarget: true }; + const sp = findSpell(b.spell); + buffCandidates.push({ ...b, mpCost: sp ? sp.mp : 0 }); } } + if (buffCandidates.length > 0) { + buffCandidates.sort((a, b) => STATE.channeling ? b.mpCost - a.mpCost : a.mpCost - b.mpCost); + return { type: 'spell', name: buffCandidates[0].spell, selfTarget: true, _reason: STATE.channeling ? 'chBuff' : 'buff' }; + } // 4. Mana/spirit items — AFTER buffs (Adept) if (STATE.mp < CFG.manaGemMP) { @@ -1447,12 +1461,20 @@ function strategyVeteran() { const ch = findBestChannelingTarget(); if (ch) return ch; } + // Collect available buff candidates and sort by cost + // No channeling → cheapest first (proc chance), channeling → most expensive (MP value) + const buffCandidates = []; for (const b of BUFF_PRIORITY) { if (shouldBuff(b.icon, b.minTurns) && STATE.mp > 0.10 && hasReadySpell(b.spell)) { if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue; - return { type: 'spell', name: b.spell, selfTarget: true, _reason: 'buff' }; + const sp = findSpell(b.spell); + buffCandidates.push({ ...b, mpCost: sp ? sp.mp : 0 }); } } + if (buffCandidates.length > 0) { + buffCandidates.sort((a, b) => STATE.channeling ? b.mpCost - a.mpCost : a.mpCost - b.mpCost); + return { type: 'spell', name: buffCandidates[0].spell, selfTarget: true, _reason: STATE.channeling ? 'chBuff' : 'buff' }; + } } // 4. Mana/spirit items — AFTER buffs (Novice) diff --git a/src/config.js b/src/config.js index 9637530..1c9f6cf 100644 --- a/src/config.js +++ b/src/config.js @@ -2,7 +2,7 @@ // CONFIG — default settings // ═══════════════════════════════════════════════════════════════════════ -const VERSION = '0.14.3'; +const VERSION = '0.14.4'; const CFG = { // — Battle automation diff --git a/src/header.user.js b/src/header.user.js index 12da18c..6888b41 100644 --- a/src/header.user.js +++ b/src/header.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name HV Unified // @namespace hvunified -// @version 0.14.3 +// @version 0.14.4 // @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse // @author GaboGG + Hermes // @match *://*.hentaiverse.org/* diff --git a/src/strategy-engine.js b/src/strategy-engine.js index d10eaf9..26d8d4c 100644 --- a/src/strategy-engine.js +++ b/src/strategy-engine.js @@ -430,12 +430,19 @@ function strategyNovice() { const ch = findBestChannelingTarget(); if (ch) return ch; } + // Collect available buff candidates and sort by cost + const buffCandidates = []; for (const b of BUFF_PRIORITY) { if (shouldBuff(b.icon, b.minTurns) && STATE.mp > 0.10 && hasReadySpell(b.spell)) { if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue; - return { type: 'spell', name: b.spell, selfTarget: true }; + const sp = findSpell(b.spell); + buffCandidates.push({ ...b, mpCost: sp ? sp.mp : 0 }); } } + if (buffCandidates.length > 0) { + buffCandidates.sort((a, b) => STATE.channeling ? b.mpCost - a.mpCost : a.mpCost - b.mpCost); + return { type: 'spell', name: buffCandidates[0].spell, selfTarget: true, _reason: STATE.channeling ? 'chBuff' : 'buff' }; + } // 4. Mana/spirit items — AFTER buffs (Novice) if (STATE.mp < CFG.manaGemMP) { @@ -566,17 +573,24 @@ function strategyAdept() { } // If channeling is active, prioritize most expensive buff for best value // Note: channeling reduces cost to ~1, but the game pre-checks base MP, - // so we skip spells we can't afford at base cost + // If channeling is active, prioritize most expensive buff for best value if (STATE.channeling && STATE.mp > 0.10) { const ch = findBestChannelingTarget(); if (ch) return ch; } + // Collect available buff candidates and sort by cost + const buffCandidates = []; for (const b of BUFF_PRIORITY) { if (shouldBuff(b.icon, b.minTurns) && STATE.mp > 0.10 && hasReadySpell(b.spell)) { if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue; - return { type: 'spell', name: b.spell, selfTarget: true }; + const sp = findSpell(b.spell); + buffCandidates.push({ ...b, mpCost: sp ? sp.mp : 0 }); } } + if (buffCandidates.length > 0) { + buffCandidates.sort((a, b) => STATE.channeling ? b.mpCost - a.mpCost : a.mpCost - b.mpCost); + return { type: 'spell', name: buffCandidates[0].spell, selfTarget: true, _reason: STATE.channeling ? 'chBuff' : 'buff' }; + } // 4. Mana/spirit items — AFTER buffs (Adept) if (STATE.mp < CFG.manaGemMP) { @@ -722,12 +736,20 @@ function strategyVeteran() { const ch = findBestChannelingTarget(); if (ch) return ch; } + // Collect available buff candidates and sort by cost + // No channeling → cheapest first (proc chance), channeling → most expensive (MP value) + const buffCandidates = []; for (const b of BUFF_PRIORITY) { if (shouldBuff(b.icon, b.minTurns) && STATE.mp > 0.10 && hasReadySpell(b.spell)) { if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue; - return { type: 'spell', name: b.spell, selfTarget: true, _reason: 'buff' }; + const sp = findSpell(b.spell); + buffCandidates.push({ ...b, mpCost: sp ? sp.mp : 0 }); } } + if (buffCandidates.length > 0) { + buffCandidates.sort((a, b) => STATE.channeling ? b.mpCost - a.mpCost : a.mpCost - b.mpCost); + return { type: 'spell', name: buffCandidates[0].spell, selfTarget: true, _reason: STATE.channeling ? 'chBuff' : 'buff' }; + } } // 4. Mana/spirit items — AFTER buffs (Novice)