v0.13.20 - Add SPELL_COSTS fallback for Mana Conservation-reduced MP costs
- Some spells show mp=1 in the DOM due to high Mana Conservation proficiency, making fill-level scoring produce near-zero values - Now: if mpCost < 5, look up the base cost from SPELL_COSTS table - This ensures Heartseeker (141 MP) scores correctly even when the DOM shows it costing 1 MP
This commit is contained in:
parent
e914c08475
commit
e20fe0495c
6 changed files with 69 additions and 9 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name HV Unified
|
// @name HV Unified
|
||||||
// @namespace hvunified
|
// @namespace hvunified
|
||||||
// @version 0.13.19
|
// @version 0.13.20
|
||||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||||
// @author GaboGG + Hermes
|
// @author GaboGG + Hermes
|
||||||
// @match *://*.hentaiverse.org/*
|
// @match *://*.hentaiverse.org/*
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
// CONFIG — default settings
|
// CONFIG — default settings
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
const VERSION = '0.13.19';
|
const VERSION = '0.13.20';
|
||||||
|
|
||||||
const CFG = {
|
const CFG = {
|
||||||
// — Battle automation
|
// — Battle automation
|
||||||
|
|
@ -580,6 +580,18 @@ function hasUsableGem(type) {
|
||||||
// KNOWLEDGE BASE — game data, spell unlocks, milestones, stat advice
|
// KNOWLEDGE BASE — game data, spell unlocks, milestones, stat advice
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
// Base MP costs for buff spells (used for channeling value calculation when
|
||||||
|
// the DOM shows Mana Conservation-reduced costs like 1 MP)
|
||||||
|
const SPELL_COSTS = {
|
||||||
|
'Absorb': 40,
|
||||||
|
'Haste': 51,
|
||||||
|
'Heartseeker': 141,
|
||||||
|
'Protection': 32,
|
||||||
|
'Regen': 71,
|
||||||
|
'Shadow Veil': 52,
|
||||||
|
'Spark of Life': 70,
|
||||||
|
};
|
||||||
|
|
||||||
const KB = {
|
const KB = {
|
||||||
qualities: ['Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary', 'Peerless'],
|
qualities: ['Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary', 'Peerless'],
|
||||||
|
|
||||||
|
|
@ -903,7 +915,15 @@ function findBestChannelingTarget() {
|
||||||
const dur = buffDuration(b.icon);
|
const dur = buffDuration(b.icon);
|
||||||
if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue;
|
if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue;
|
||||||
const sp = findSpell(b.spell);
|
const sp = findSpell(b.spell);
|
||||||
const mpCost = sp ? sp.mp : 0;
|
// Use a reasonable MP cost: ignore Mana Conservation-reduced values
|
||||||
|
// (the DOM may show 1 MP at high proficiency, but the real base cost
|
||||||
|
// determines the savings from a free channeling cast)
|
||||||
|
let mpCost = sp ? sp.mp : 0;
|
||||||
|
if (mpCost > 0 && mpCost < 5 && sp) {
|
||||||
|
// Try to get base cost from knowledge-base
|
||||||
|
const kb = SPELL_COSTS[b.spell];
|
||||||
|
if (kb) mpCost = kb;
|
||||||
|
}
|
||||||
// Fill level: how empty is this buff relative to its max observed duration
|
// Fill level: how empty is this buff relative to its max observed duration
|
||||||
let maxDur = STATE.maxBuffDur[b.icon] || 0;
|
let maxDur = STATE.maxBuffDur[b.icon] || 0;
|
||||||
// If max matches current (first observation, no learning yet), assume min 30 turns
|
// If max matches current (first observation, no learning yet), assume min 30 turns
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name HV Unified
|
// @name HV Unified
|
||||||
// @namespace hvunified
|
// @namespace hvunified
|
||||||
// @version 0.13.19
|
// @version 0.13.20
|
||||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||||
// @author GaboGG + Hermes
|
// @author GaboGG + Hermes
|
||||||
// @match *://*.hentaiverse.org/*
|
// @match *://*.hentaiverse.org/*
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
// CONFIG — default settings
|
// CONFIG — default settings
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
const VERSION = '0.13.19';
|
const VERSION = '0.13.20';
|
||||||
|
|
||||||
const CFG = {
|
const CFG = {
|
||||||
// — Battle automation
|
// — Battle automation
|
||||||
|
|
@ -580,6 +580,18 @@ function hasUsableGem(type) {
|
||||||
// KNOWLEDGE BASE — game data, spell unlocks, milestones, stat advice
|
// KNOWLEDGE BASE — game data, spell unlocks, milestones, stat advice
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
// Base MP costs for buff spells (used for channeling value calculation when
|
||||||
|
// the DOM shows Mana Conservation-reduced costs like 1 MP)
|
||||||
|
const SPELL_COSTS = {
|
||||||
|
'Absorb': 40,
|
||||||
|
'Haste': 51,
|
||||||
|
'Heartseeker': 141,
|
||||||
|
'Protection': 32,
|
||||||
|
'Regen': 71,
|
||||||
|
'Shadow Veil': 52,
|
||||||
|
'Spark of Life': 70,
|
||||||
|
};
|
||||||
|
|
||||||
const KB = {
|
const KB = {
|
||||||
qualities: ['Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary', 'Peerless'],
|
qualities: ['Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary', 'Peerless'],
|
||||||
|
|
||||||
|
|
@ -903,7 +915,15 @@ function findBestChannelingTarget() {
|
||||||
const dur = buffDuration(b.icon);
|
const dur = buffDuration(b.icon);
|
||||||
if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue;
|
if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue;
|
||||||
const sp = findSpell(b.spell);
|
const sp = findSpell(b.spell);
|
||||||
const mpCost = sp ? sp.mp : 0;
|
// Use a reasonable MP cost: ignore Mana Conservation-reduced values
|
||||||
|
// (the DOM may show 1 MP at high proficiency, but the real base cost
|
||||||
|
// determines the savings from a free channeling cast)
|
||||||
|
let mpCost = sp ? sp.mp : 0;
|
||||||
|
if (mpCost > 0 && mpCost < 5 && sp) {
|
||||||
|
// Try to get base cost from knowledge-base
|
||||||
|
const kb = SPELL_COSTS[b.spell];
|
||||||
|
if (kb) mpCost = kb;
|
||||||
|
}
|
||||||
// Fill level: how empty is this buff relative to its max observed duration
|
// Fill level: how empty is this buff relative to its max observed duration
|
||||||
let maxDur = STATE.maxBuffDur[b.icon] || 0;
|
let maxDur = STATE.maxBuffDur[b.icon] || 0;
|
||||||
// If max matches current (first observation, no learning yet), assume min 30 turns
|
// If max matches current (first observation, no learning yet), assume min 30 turns
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// CONFIG — default settings
|
// CONFIG — default settings
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
const VERSION = '0.13.19';
|
const VERSION = '0.13.20';
|
||||||
|
|
||||||
const CFG = {
|
const CFG = {
|
||||||
// — Battle automation
|
// — Battle automation
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name HV Unified
|
// @name HV Unified
|
||||||
// @namespace hvunified
|
// @namespace hvunified
|
||||||
// @version 0.13.19
|
// @version 0.13.20
|
||||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||||
// @author GaboGG + Hermes
|
// @author GaboGG + Hermes
|
||||||
// @match *://*.hentaiverse.org/*
|
// @match *://*.hentaiverse.org/*
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,18 @@
|
||||||
// KNOWLEDGE BASE — game data, spell unlocks, milestones, stat advice
|
// KNOWLEDGE BASE — game data, spell unlocks, milestones, stat advice
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
// Base MP costs for buff spells (used for channeling value calculation when
|
||||||
|
// the DOM shows Mana Conservation-reduced costs like 1 MP)
|
||||||
|
const SPELL_COSTS = {
|
||||||
|
'Absorb': 40,
|
||||||
|
'Haste': 51,
|
||||||
|
'Heartseeker': 141,
|
||||||
|
'Protection': 32,
|
||||||
|
'Regen': 71,
|
||||||
|
'Shadow Veil': 52,
|
||||||
|
'Spark of Life': 70,
|
||||||
|
};
|
||||||
|
|
||||||
const KB = {
|
const KB = {
|
||||||
qualities: ['Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary', 'Peerless'],
|
qualities: ['Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary', 'Peerless'],
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,15 @@ function findBestChannelingTarget() {
|
||||||
const dur = buffDuration(b.icon);
|
const dur = buffDuration(b.icon);
|
||||||
if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue;
|
if (b.icon === 'regen' && STATE.hp >= CFG.cureRegenHP) continue;
|
||||||
const sp = findSpell(b.spell);
|
const sp = findSpell(b.spell);
|
||||||
const mpCost = sp ? sp.mp : 0;
|
// Use a reasonable MP cost: ignore Mana Conservation-reduced values
|
||||||
|
// (the DOM may show 1 MP at high proficiency, but the real base cost
|
||||||
|
// determines the savings from a free channeling cast)
|
||||||
|
let mpCost = sp ? sp.mp : 0;
|
||||||
|
if (mpCost > 0 && mpCost < 5 && sp) {
|
||||||
|
// Try to get base cost from knowledge-base
|
||||||
|
const kb = SPELL_COSTS[b.spell];
|
||||||
|
if (kb) mpCost = kb;
|
||||||
|
}
|
||||||
// Fill level: how empty is this buff relative to its max observed duration
|
// Fill level: how empty is this buff relative to its max observed duration
|
||||||
let maxDur = STATE.maxBuffDur[b.icon] || 0;
|
let maxDur = STATE.maxBuffDur[b.icon] || 0;
|
||||||
// If max matches current (first observation, no learning yet), assume min 30 turns
|
// If max matches current (first observation, no learning yet), assume min 30 turns
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue