v0.17.2 - Fix chainState ref, lazy jpx detection, diag visibility
- Fix: chainState/chain used renamed var (jpxChainEnabled vs jpxChainStarted) - Fix: jpxChainStart lazy-retries (10x/600ms) since jpx creates #ctrl-widget lazily - Remove duplicate jpxChainStart definition - HV.diag() now reports scripts.jpx + jpxBridge state for field diagnosis
This commit is contained in:
parent
68b44e022a
commit
30bade19bd
6 changed files with 105 additions and 54 deletions
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name HV Unified
|
||||
// @namespace hvunified
|
||||
// @version 0.17.1
|
||||
// @version 0.17.2
|
||||
// @description HV Unified — Bridge & Strategy/Gear Advisor for HentaiVerse (complements Monsterbation & HVUtils)
|
||||
// @author GaboGG + Hermes
|
||||
// @match *://*.hentaiverse.org/*
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
// CONFIG — default settings
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
const VERSION = '0.17.1';
|
||||
const VERSION = '0.17.2';
|
||||
|
||||
const CFG = {
|
||||
// — Battle strategy advisory
|
||||
|
|
@ -1568,6 +1568,29 @@ function jpxPresent() {
|
|||
document.querySelector('#ctrl-widget, .ctrl-widget'));
|
||||
}
|
||||
|
||||
// Lazy-start: retry until jpx's widget actually appears (it's created lazily
|
||||
// by jpx after its init, so our first check may be too early).
|
||||
function jpxChainStart() {
|
||||
if (!CFG.autoChainJpx) return;
|
||||
if (jpxChainEnabled) return;
|
||||
if (!jpxPresent()) {
|
||||
// Retry a few times over ~6s before giving up
|
||||
if (!jpxChainRetryCount) jpxChainRetryCount = 0;
|
||||
if (jpxChainRetryCount < 10) {
|
||||
jpxChainRetryCount++;
|
||||
setTimeout(jpxChainStart, 600);
|
||||
}
|
||||
return;
|
||||
}
|
||||
jpxChainRetryCount = 0;
|
||||
jpxChainEnabled = true;
|
||||
jpxChainRounds = 0;
|
||||
jpxChainCooldown = Date.now();
|
||||
// Start the first auto round (equivalent to pressing M once)
|
||||
setTimeout(jpxTriggerAuto, 800);
|
||||
console.log('%c[HV] ⛓ jpx auto-chain engaged (re-triggering M each round)', 'color:#0f0');
|
||||
}
|
||||
|
||||
// Trigger jpx's auto-battle toggle (equivalent to pressing M).
|
||||
// jpx listens for keydown on document (capture phase) and maps key 'm' to
|
||||
// toggleActive via userKeybinds. A synthetic KeyboardEvent works because
|
||||
|
|
@ -1603,20 +1626,6 @@ function jpxBattleOver() {
|
|||
return !jpxMonstersPresent();
|
||||
}
|
||||
|
||||
// Start the chain (called after battle initializes)
|
||||
function jpxChainStart() {
|
||||
if (!CFG.autoChainJpx) return;
|
||||
if (jpxChainEnabled) return;
|
||||
if (!jpxPresent()) return;
|
||||
|
||||
jpxChainEnabled = true;
|
||||
jpxChainRounds = 0;
|
||||
jpxChainCooldown = Date.now();
|
||||
// Start the first auto round (equivalent to pressing M once)
|
||||
setTimeout(jpxTriggerAuto, 800);
|
||||
console.log('%c[HV] ⛓ jpx auto-chain engaged (re-triggering M each round)', 'color:#0f0');
|
||||
}
|
||||
|
||||
// Called when jpx reports a state change via jpx_ctrlWidget_update
|
||||
function jpxChainOnState(detail) {
|
||||
if (!CFG.autoChainJpx) return;
|
||||
|
|
@ -3765,8 +3774,8 @@ window.HV = {
|
|||
stats: () => JSON.parse(localStorage[SP + 'stats'] || '{"battles":0,"credits":0,"drops":0}'),
|
||||
settings: () => toggleSettings(),
|
||||
// jpx bridge control
|
||||
chain: (on) => { CFG.autoChainJpx = !!on; saveConfig(); if (on) { jpxChainStart(); if (!jpxChainTimer) jpxChainTimer = setInterval(jpxChainTick, 1500); } else { jpxChainStop('manual'); } return 'jpx chain: ' + CFG.autoChainJpx; },
|
||||
chainState: () => ({ active: jpxChainStarted, rounds: jpxChainRounds, jpx: jpxPresent(), maxRounds: CFG.chainMaxRounds, minHP: CFG.chainMinHP }),
|
||||
chain: (on) => { CFG.autoChainJpx = !!on; saveConfig(); if (on) { jpxBridgeWire(); jpxChainStart(); } else { jpxChainStop('manual'); } return 'jpx chain: ' + CFG.autoChainJpx; },
|
||||
chainState: () => ({ active: jpxChainEnabled, rounds: jpxChainRounds, jpx: jpxPresent(), maxRounds: CFG.chainMaxRounds, minHP: CFG.chainMinHP }),
|
||||
advice: () => {
|
||||
const s = detectFightingStyle();
|
||||
return { style: s, attrs: getAttrAdvice(s), spells: getSpellAdvice(), difficulty: getDifficultyAdvice() };
|
||||
|
|
@ -3805,8 +3814,16 @@ window.HV = {
|
|||
document.getElementById('hvut') ||
|
||||
window.HVUT ||
|
||||
document.querySelector('[class*="hvut"], [id*="hvut"]')),
|
||||
jpx: jpxPresent(),
|
||||
unified: true,
|
||||
},
|
||||
// jpx bridge state
|
||||
jpxBridge: {
|
||||
chainEnabled: jpxChainEnabled,
|
||||
chainRounds: jpxChainRounds,
|
||||
jpxLastActive: jpxLastActive,
|
||||
retryCount: jpxChainRetryCount || 0,
|
||||
},
|
||||
// State availability
|
||||
state_ready: !!STATE && !!STATE.page,
|
||||
monsters: STATE.monsters ? STATE.monsters.length : null,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name HV Unified
|
||||
// @namespace hvunified
|
||||
// @version 0.17.1
|
||||
// @version 0.17.2
|
||||
// @description HV Unified — Bridge & Strategy/Gear Advisor for HentaiVerse (complements Monsterbation & HVUtils)
|
||||
// @author GaboGG + Hermes
|
||||
// @match *://*.hentaiverse.org/*
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
// CONFIG — default settings
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
const VERSION = '0.17.1';
|
||||
const VERSION = '0.17.2';
|
||||
|
||||
const CFG = {
|
||||
// — Battle strategy advisory
|
||||
|
|
@ -1568,6 +1568,29 @@ function jpxPresent() {
|
|||
document.querySelector('#ctrl-widget, .ctrl-widget'));
|
||||
}
|
||||
|
||||
// Lazy-start: retry until jpx's widget actually appears (it's created lazily
|
||||
// by jpx after its init, so our first check may be too early).
|
||||
function jpxChainStart() {
|
||||
if (!CFG.autoChainJpx) return;
|
||||
if (jpxChainEnabled) return;
|
||||
if (!jpxPresent()) {
|
||||
// Retry a few times over ~6s before giving up
|
||||
if (!jpxChainRetryCount) jpxChainRetryCount = 0;
|
||||
if (jpxChainRetryCount < 10) {
|
||||
jpxChainRetryCount++;
|
||||
setTimeout(jpxChainStart, 600);
|
||||
}
|
||||
return;
|
||||
}
|
||||
jpxChainRetryCount = 0;
|
||||
jpxChainEnabled = true;
|
||||
jpxChainRounds = 0;
|
||||
jpxChainCooldown = Date.now();
|
||||
// Start the first auto round (equivalent to pressing M once)
|
||||
setTimeout(jpxTriggerAuto, 800);
|
||||
console.log('%c[HV] ⛓ jpx auto-chain engaged (re-triggering M each round)', 'color:#0f0');
|
||||
}
|
||||
|
||||
// Trigger jpx's auto-battle toggle (equivalent to pressing M).
|
||||
// jpx listens for keydown on document (capture phase) and maps key 'm' to
|
||||
// toggleActive via userKeybinds. A synthetic KeyboardEvent works because
|
||||
|
|
@ -1603,20 +1626,6 @@ function jpxBattleOver() {
|
|||
return !jpxMonstersPresent();
|
||||
}
|
||||
|
||||
// Start the chain (called after battle initializes)
|
||||
function jpxChainStart() {
|
||||
if (!CFG.autoChainJpx) return;
|
||||
if (jpxChainEnabled) return;
|
||||
if (!jpxPresent()) return;
|
||||
|
||||
jpxChainEnabled = true;
|
||||
jpxChainRounds = 0;
|
||||
jpxChainCooldown = Date.now();
|
||||
// Start the first auto round (equivalent to pressing M once)
|
||||
setTimeout(jpxTriggerAuto, 800);
|
||||
console.log('%c[HV] ⛓ jpx auto-chain engaged (re-triggering M each round)', 'color:#0f0');
|
||||
}
|
||||
|
||||
// Called when jpx reports a state change via jpx_ctrlWidget_update
|
||||
function jpxChainOnState(detail) {
|
||||
if (!CFG.autoChainJpx) return;
|
||||
|
|
@ -3765,8 +3774,8 @@ window.HV = {
|
|||
stats: () => JSON.parse(localStorage[SP + 'stats'] || '{"battles":0,"credits":0,"drops":0}'),
|
||||
settings: () => toggleSettings(),
|
||||
// jpx bridge control
|
||||
chain: (on) => { CFG.autoChainJpx = !!on; saveConfig(); if (on) { jpxChainStart(); if (!jpxChainTimer) jpxChainTimer = setInterval(jpxChainTick, 1500); } else { jpxChainStop('manual'); } return 'jpx chain: ' + CFG.autoChainJpx; },
|
||||
chainState: () => ({ active: jpxChainStarted, rounds: jpxChainRounds, jpx: jpxPresent(), maxRounds: CFG.chainMaxRounds, minHP: CFG.chainMinHP }),
|
||||
chain: (on) => { CFG.autoChainJpx = !!on; saveConfig(); if (on) { jpxBridgeWire(); jpxChainStart(); } else { jpxChainStop('manual'); } return 'jpx chain: ' + CFG.autoChainJpx; },
|
||||
chainState: () => ({ active: jpxChainEnabled, rounds: jpxChainRounds, jpx: jpxPresent(), maxRounds: CFG.chainMaxRounds, minHP: CFG.chainMinHP }),
|
||||
advice: () => {
|
||||
const s = detectFightingStyle();
|
||||
return { style: s, attrs: getAttrAdvice(s), spells: getSpellAdvice(), difficulty: getDifficultyAdvice() };
|
||||
|
|
@ -3805,8 +3814,16 @@ window.HV = {
|
|||
document.getElementById('hvut') ||
|
||||
window.HVUT ||
|
||||
document.querySelector('[class*="hvut"], [id*="hvut"]')),
|
||||
jpx: jpxPresent(),
|
||||
unified: true,
|
||||
},
|
||||
// jpx bridge state
|
||||
jpxBridge: {
|
||||
chainEnabled: jpxChainEnabled,
|
||||
chainRounds: jpxChainRounds,
|
||||
jpxLastActive: jpxLastActive,
|
||||
retryCount: jpxChainRetryCount || 0,
|
||||
},
|
||||
// State availability
|
||||
state_ready: !!STATE && !!STATE.page,
|
||||
monsters: STATE.monsters ? STATE.monsters.length : null,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// CONFIG — default settings
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
const VERSION = '0.17.1';
|
||||
const VERSION = '0.17.2';
|
||||
|
||||
const CFG = {
|
||||
// — Battle strategy advisory
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name HV Unified
|
||||
// @namespace hvunified
|
||||
// @version 0.17.1
|
||||
// @version 0.17.2
|
||||
// @description HV Unified — Bridge & Strategy/Gear Advisor for HentaiVerse (complements Monsterbation & HVUtils)
|
||||
// @author GaboGG + Hermes
|
||||
// @match *://*.hentaiverse.org/*
|
||||
|
|
|
|||
|
|
@ -21,6 +21,29 @@ function jpxPresent() {
|
|||
document.querySelector('#ctrl-widget, .ctrl-widget'));
|
||||
}
|
||||
|
||||
// Lazy-start: retry until jpx's widget actually appears (it's created lazily
|
||||
// by jpx after its init, so our first check may be too early).
|
||||
function jpxChainStart() {
|
||||
if (!CFG.autoChainJpx) return;
|
||||
if (jpxChainEnabled) return;
|
||||
if (!jpxPresent()) {
|
||||
// Retry a few times over ~6s before giving up
|
||||
if (!jpxChainRetryCount) jpxChainRetryCount = 0;
|
||||
if (jpxChainRetryCount < 10) {
|
||||
jpxChainRetryCount++;
|
||||
setTimeout(jpxChainStart, 600);
|
||||
}
|
||||
return;
|
||||
}
|
||||
jpxChainRetryCount = 0;
|
||||
jpxChainEnabled = true;
|
||||
jpxChainRounds = 0;
|
||||
jpxChainCooldown = Date.now();
|
||||
// Start the first auto round (equivalent to pressing M once)
|
||||
setTimeout(jpxTriggerAuto, 800);
|
||||
console.log('%c[HV] ⛓ jpx auto-chain engaged (re-triggering M each round)', 'color:#0f0');
|
||||
}
|
||||
|
||||
// Trigger jpx's auto-battle toggle (equivalent to pressing M).
|
||||
// jpx listens for keydown on document (capture phase) and maps key 'm' to
|
||||
// toggleActive via userKeybinds. A synthetic KeyboardEvent works because
|
||||
|
|
@ -56,20 +79,6 @@ function jpxBattleOver() {
|
|||
return !jpxMonstersPresent();
|
||||
}
|
||||
|
||||
// Start the chain (called after battle initializes)
|
||||
function jpxChainStart() {
|
||||
if (!CFG.autoChainJpx) return;
|
||||
if (jpxChainEnabled) return;
|
||||
if (!jpxPresent()) return;
|
||||
|
||||
jpxChainEnabled = true;
|
||||
jpxChainRounds = 0;
|
||||
jpxChainCooldown = Date.now();
|
||||
// Start the first auto round (equivalent to pressing M once)
|
||||
setTimeout(jpxTriggerAuto, 800);
|
||||
console.log('%c[HV] ⛓ jpx auto-chain engaged (re-triggering M each round)', 'color:#0f0');
|
||||
}
|
||||
|
||||
// Called when jpx reports a state change via jpx_ctrlWidget_update
|
||||
function jpxChainOnState(detail) {
|
||||
if (!CFG.autoChainJpx) return;
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ window.HV = {
|
|||
stats: () => JSON.parse(localStorage[SP + 'stats'] || '{"battles":0,"credits":0,"drops":0}'),
|
||||
settings: () => toggleSettings(),
|
||||
// jpx bridge control
|
||||
chain: (on) => { CFG.autoChainJpx = !!on; saveConfig(); if (on) { jpxChainStart(); if (!jpxChainTimer) jpxChainTimer = setInterval(jpxChainTick, 1500); } else { jpxChainStop('manual'); } return 'jpx chain: ' + CFG.autoChainJpx; },
|
||||
chainState: () => ({ active: jpxChainStarted, rounds: jpxChainRounds, jpx: jpxPresent(), maxRounds: CFG.chainMaxRounds, minHP: CFG.chainMinHP }),
|
||||
chain: (on) => { CFG.autoChainJpx = !!on; saveConfig(); if (on) { jpxBridgeWire(); jpxChainStart(); } else { jpxChainStop('manual'); } return 'jpx chain: ' + CFG.autoChainJpx; },
|
||||
chainState: () => ({ active: jpxChainEnabled, rounds: jpxChainRounds, jpx: jpxPresent(), maxRounds: CFG.chainMaxRounds, minHP: CFG.chainMinHP }),
|
||||
advice: () => {
|
||||
const s = detectFightingStyle();
|
||||
return { style: s, attrs: getAttrAdvice(s), spells: getSpellAdvice(), difficulty: getDifficultyAdvice() };
|
||||
|
|
@ -52,8 +52,16 @@ window.HV = {
|
|||
document.getElementById('hvut') ||
|
||||
window.HVUT ||
|
||||
document.querySelector('[class*="hvut"], [id*="hvut"]')),
|
||||
jpx: jpxPresent(),
|
||||
unified: true,
|
||||
},
|
||||
// jpx bridge state
|
||||
jpxBridge: {
|
||||
chainEnabled: jpxChainEnabled,
|
||||
chainRounds: jpxChainRounds,
|
||||
jpxLastActive: jpxLastActive,
|
||||
retryCount: jpxChainRetryCount || 0,
|
||||
},
|
||||
// State availability
|
||||
state_ready: !!STATE && !!STATE.page,
|
||||
monsters: STATE.monsters ? STATE.monsters.length : null,
|
||||
|
|
|
|||
Loading…
Reference in a new issue