- Removed SPELL_COSTS hardcoded table - Base MP costs are now read from the magic pane's onmouseover tooltip at battle init and cached in STATE._baseMpCosts - Cache is populated during parseBattleState() and persists for the entire battle, avoiding channeling's 1-MP display - Cache resets on new battle, so level-ups or stat changes are picked up when starting a new arena
121 lines
4.5 KiB
JavaScript
121 lines
4.5 KiB
JavaScript
// ═══════════════════════════════════════════════════════════════════════
|
||
// INIT — bootstrap everything
|
||
// ═══════════════════════════════════════════════════════════════════════
|
||
|
||
function init() {
|
||
loadConfig();
|
||
detectLevel();
|
||
STATE.page = detectPage();
|
||
|
||
// Always-on features
|
||
setupRETimer();
|
||
addConfigButton();
|
||
renderProgressPanel();
|
||
|
||
if (STATE.page === 'battle') {
|
||
initializeBattle();
|
||
autoCheckTask('battle');
|
||
} else {
|
||
// Non-battle page enhancements
|
||
if (STATE.page === 'itemshop') { enhanceItemShop(); autoCheckTask('buy-health'); }
|
||
if (STATE.page === 'equipshop') { enhanceEquipShopWithAdvice(); }
|
||
if (STATE.page === 'shrine') enhanceShrine();
|
||
if (STATE.page === 'training') { enhanceTraining(); autoCheckTask('training'); }
|
||
if (STATE.page === 'monsterlab') { enhanceMonsterLab(); autoCheckTask('feed'); }
|
||
if (STATE.page === 'arena') { autoCheckTask('arenas'); autoCheckTask('first-blood'); }
|
||
if (STATE.page === 'character') showGuidancePanel();
|
||
if (STATE.page === 'settings') enhanceSettings();
|
||
if (STATE.page === 'armory') enhanceArmory();
|
||
if (STATE.page === 'abilities') enhanceAbilities();
|
||
if (STATE.page === 'monster') enhanceMonsterLab();
|
||
}
|
||
|
||
// Dawn initialization
|
||
if (!localStorage[SP + 'lastDawn']) {
|
||
try { localStorage[SP + 'lastDawn'] = JSON.stringify(Date.now()); } catch (e) {}
|
||
}
|
||
updateRETimer();
|
||
|
||
// Watch for dynamic page transitions (arena/grindfest → battle)
|
||
const bodyObserver = new MutationObserver(() => {
|
||
if (!STATE.inBattle && isBattlePage()) {
|
||
initializeBattle();
|
||
}
|
||
});
|
||
bodyObserver.observe(document.body, { childList: true, subtree: true });
|
||
}
|
||
|
||
function initializeBattle() {
|
||
if (STATE.battleInitialized && STATE.page === 'battle') return;
|
||
STATE.page = 'battle';
|
||
STATE.inBattle = true;
|
||
STATE._mysticUsed = false; // Reset Mystic Gem tracking on new battle
|
||
STATE._baseMpCosts = {}; // Reset base cost cache
|
||
|
||
parseBattleState();
|
||
// Force tier update from cached level (battle page may not have level_readout)
|
||
if (STATE.level > 1) updateTier();
|
||
setupHover();
|
||
setupKeybindings();
|
||
addMonsterNumbers();
|
||
refreshUI();
|
||
addConfigButton();
|
||
showDifficultyBanner();
|
||
|
||
// Watch battle log
|
||
const log = document.getElementById('textlog');
|
||
if (log && !log.dataset.hvObserved) {
|
||
log.dataset.hvObserved = '1';
|
||
const obs = new MutationObserver(() => {
|
||
parseBattleState();
|
||
saveMonsterData();
|
||
logRound(); // Log this round's data for analysis
|
||
if (CFG.hoverEnabled && !STATE.interruptHover && !STATE.interruptAlert && STATE.hoverTarget >= 0) {
|
||
const a = getSmartAction();
|
||
if (a) executeAction(a);
|
||
}
|
||
refreshUI();
|
||
updateConfigButton();
|
||
});
|
||
obs.observe(log, { childList: true, subtree: true, characterData: true });
|
||
}
|
||
|
||
// Watch vitals pane
|
||
const vitals = document.getElementById('pane_vitals');
|
||
if (vitals && !vitals.dataset.hvObserved) {
|
||
vitals.dataset.hvObserved = '1';
|
||
const vobs = new MutationObserver(() => {
|
||
parseBattleState();
|
||
logRound(); // Also log on vitals changes (catches end-of-round)
|
||
refreshUI();
|
||
updateConfigButton();
|
||
// Check if battle ended (completion pane appeared)
|
||
if (document.getElementById('pane_completion')) {
|
||
// Battle ended — handled by log observer
|
||
}
|
||
});
|
||
vobs.observe(vitals, { childList: true, subtree: true, attributes: true });
|
||
}
|
||
|
||
// RiddleMaster detection
|
||
if (document.getElementById('riddlemaster')) {
|
||
STATE.interruptHover = true;
|
||
}
|
||
|
||
STATE.battleInitialized = true;
|
||
}
|
||
|
||
// ── Bootstrap ──
|
||
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', init);
|
||
} else {
|
||
init();
|
||
}
|
||
|
||
console.log('%c🛡️ HV Unified v' + VERSION + '%c | Q=action H=hover C=cure ,=settings',
|
||
'color:#fdcb00;font-weight:bold', '');
|
||
console.log('%c HV.advice() for guidance | HV.difficulty() for difficulty check',
|
||
'color:#888;font-size:10px');
|
||
|
||
})();
|