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==
|
// ==UserScript==
|
||||||
// @name HV Unified
|
// @name HV Unified
|
||||||
// @namespace hvunified
|
// @namespace hvunified
|
||||||
// @version 0.17.1
|
// @version 0.17.2
|
||||||
// @description HV Unified — Bridge & Strategy/Gear Advisor for HentaiVerse (complements Monsterbation & HVUtils)
|
// @description HV Unified — Bridge & Strategy/Gear Advisor for HentaiVerse (complements Monsterbation & HVUtils)
|
||||||
// @author GaboGG + Hermes
|
// @author GaboGG + Hermes
|
||||||
// @match *://*.hentaiverse.org/*
|
// @match *://*.hentaiverse.org/*
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
// CONFIG — default settings
|
// CONFIG — default settings
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
const VERSION = '0.17.1';
|
const VERSION = '0.17.2';
|
||||||
|
|
||||||
const CFG = {
|
const CFG = {
|
||||||
// — Battle strategy advisory
|
// — Battle strategy advisory
|
||||||
|
|
@ -1568,6 +1568,29 @@ function jpxPresent() {
|
||||||
document.querySelector('#ctrl-widget, .ctrl-widget'));
|
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).
|
// Trigger jpx's auto-battle toggle (equivalent to pressing M).
|
||||||
// jpx listens for keydown on document (capture phase) and maps key 'm' to
|
// jpx listens for keydown on document (capture phase) and maps key 'm' to
|
||||||
// toggleActive via userKeybinds. A synthetic KeyboardEvent works because
|
// toggleActive via userKeybinds. A synthetic KeyboardEvent works because
|
||||||
|
|
@ -1603,20 +1626,6 @@ function jpxBattleOver() {
|
||||||
return !jpxMonstersPresent();
|
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
|
// Called when jpx reports a state change via jpx_ctrlWidget_update
|
||||||
function jpxChainOnState(detail) {
|
function jpxChainOnState(detail) {
|
||||||
if (!CFG.autoChainJpx) return;
|
if (!CFG.autoChainJpx) return;
|
||||||
|
|
@ -3765,8 +3774,8 @@ window.HV = {
|
||||||
stats: () => JSON.parse(localStorage[SP + 'stats'] || '{"battles":0,"credits":0,"drops":0}'),
|
stats: () => JSON.parse(localStorage[SP + 'stats'] || '{"battles":0,"credits":0,"drops":0}'),
|
||||||
settings: () => toggleSettings(),
|
settings: () => toggleSettings(),
|
||||||
// jpx bridge control
|
// 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; },
|
chain: (on) => { CFG.autoChainJpx = !!on; saveConfig(); if (on) { jpxBridgeWire(); jpxChainStart(); } else { jpxChainStop('manual'); } return 'jpx chain: ' + CFG.autoChainJpx; },
|
||||||
chainState: () => ({ active: jpxChainStarted, rounds: jpxChainRounds, jpx: jpxPresent(), maxRounds: CFG.chainMaxRounds, minHP: CFG.chainMinHP }),
|
chainState: () => ({ active: jpxChainEnabled, rounds: jpxChainRounds, jpx: jpxPresent(), maxRounds: CFG.chainMaxRounds, minHP: CFG.chainMinHP }),
|
||||||
advice: () => {
|
advice: () => {
|
||||||
const s = detectFightingStyle();
|
const s = detectFightingStyle();
|
||||||
return { style: s, attrs: getAttrAdvice(s), spells: getSpellAdvice(), difficulty: getDifficultyAdvice() };
|
return { style: s, attrs: getAttrAdvice(s), spells: getSpellAdvice(), difficulty: getDifficultyAdvice() };
|
||||||
|
|
@ -3805,8 +3814,16 @@ window.HV = {
|
||||||
document.getElementById('hvut') ||
|
document.getElementById('hvut') ||
|
||||||
window.HVUT ||
|
window.HVUT ||
|
||||||
document.querySelector('[class*="hvut"], [id*="hvut"]')),
|
document.querySelector('[class*="hvut"], [id*="hvut"]')),
|
||||||
|
jpx: jpxPresent(),
|
||||||
unified: true,
|
unified: true,
|
||||||
},
|
},
|
||||||
|
// jpx bridge state
|
||||||
|
jpxBridge: {
|
||||||
|
chainEnabled: jpxChainEnabled,
|
||||||
|
chainRounds: jpxChainRounds,
|
||||||
|
jpxLastActive: jpxLastActive,
|
||||||
|
retryCount: jpxChainRetryCount || 0,
|
||||||
|
},
|
||||||
// State availability
|
// State availability
|
||||||
state_ready: !!STATE && !!STATE.page,
|
state_ready: !!STATE && !!STATE.page,
|
||||||
monsters: STATE.monsters ? STATE.monsters.length : null,
|
monsters: STATE.monsters ? STATE.monsters.length : null,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name HV Unified
|
// @name HV Unified
|
||||||
// @namespace hvunified
|
// @namespace hvunified
|
||||||
// @version 0.17.1
|
// @version 0.17.2
|
||||||
// @description HV Unified — Bridge & Strategy/Gear Advisor for HentaiVerse (complements Monsterbation & HVUtils)
|
// @description HV Unified — Bridge & Strategy/Gear Advisor for HentaiVerse (complements Monsterbation & HVUtils)
|
||||||
// @author GaboGG + Hermes
|
// @author GaboGG + Hermes
|
||||||
// @match *://*.hentaiverse.org/*
|
// @match *://*.hentaiverse.org/*
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
// CONFIG — default settings
|
// CONFIG — default settings
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
const VERSION = '0.17.1';
|
const VERSION = '0.17.2';
|
||||||
|
|
||||||
const CFG = {
|
const CFG = {
|
||||||
// — Battle strategy advisory
|
// — Battle strategy advisory
|
||||||
|
|
@ -1568,6 +1568,29 @@ function jpxPresent() {
|
||||||
document.querySelector('#ctrl-widget, .ctrl-widget'));
|
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).
|
// Trigger jpx's auto-battle toggle (equivalent to pressing M).
|
||||||
// jpx listens for keydown on document (capture phase) and maps key 'm' to
|
// jpx listens for keydown on document (capture phase) and maps key 'm' to
|
||||||
// toggleActive via userKeybinds. A synthetic KeyboardEvent works because
|
// toggleActive via userKeybinds. A synthetic KeyboardEvent works because
|
||||||
|
|
@ -1603,20 +1626,6 @@ function jpxBattleOver() {
|
||||||
return !jpxMonstersPresent();
|
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
|
// Called when jpx reports a state change via jpx_ctrlWidget_update
|
||||||
function jpxChainOnState(detail) {
|
function jpxChainOnState(detail) {
|
||||||
if (!CFG.autoChainJpx) return;
|
if (!CFG.autoChainJpx) return;
|
||||||
|
|
@ -3765,8 +3774,8 @@ window.HV = {
|
||||||
stats: () => JSON.parse(localStorage[SP + 'stats'] || '{"battles":0,"credits":0,"drops":0}'),
|
stats: () => JSON.parse(localStorage[SP + 'stats'] || '{"battles":0,"credits":0,"drops":0}'),
|
||||||
settings: () => toggleSettings(),
|
settings: () => toggleSettings(),
|
||||||
// jpx bridge control
|
// 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; },
|
chain: (on) => { CFG.autoChainJpx = !!on; saveConfig(); if (on) { jpxBridgeWire(); jpxChainStart(); } else { jpxChainStop('manual'); } return 'jpx chain: ' + CFG.autoChainJpx; },
|
||||||
chainState: () => ({ active: jpxChainStarted, rounds: jpxChainRounds, jpx: jpxPresent(), maxRounds: CFG.chainMaxRounds, minHP: CFG.chainMinHP }),
|
chainState: () => ({ active: jpxChainEnabled, rounds: jpxChainRounds, jpx: jpxPresent(), maxRounds: CFG.chainMaxRounds, minHP: CFG.chainMinHP }),
|
||||||
advice: () => {
|
advice: () => {
|
||||||
const s = detectFightingStyle();
|
const s = detectFightingStyle();
|
||||||
return { style: s, attrs: getAttrAdvice(s), spells: getSpellAdvice(), difficulty: getDifficultyAdvice() };
|
return { style: s, attrs: getAttrAdvice(s), spells: getSpellAdvice(), difficulty: getDifficultyAdvice() };
|
||||||
|
|
@ -3805,8 +3814,16 @@ window.HV = {
|
||||||
document.getElementById('hvut') ||
|
document.getElementById('hvut') ||
|
||||||
window.HVUT ||
|
window.HVUT ||
|
||||||
document.querySelector('[class*="hvut"], [id*="hvut"]')),
|
document.querySelector('[class*="hvut"], [id*="hvut"]')),
|
||||||
|
jpx: jpxPresent(),
|
||||||
unified: true,
|
unified: true,
|
||||||
},
|
},
|
||||||
|
// jpx bridge state
|
||||||
|
jpxBridge: {
|
||||||
|
chainEnabled: jpxChainEnabled,
|
||||||
|
chainRounds: jpxChainRounds,
|
||||||
|
jpxLastActive: jpxLastActive,
|
||||||
|
retryCount: jpxChainRetryCount || 0,
|
||||||
|
},
|
||||||
// State availability
|
// State availability
|
||||||
state_ready: !!STATE && !!STATE.page,
|
state_ready: !!STATE && !!STATE.page,
|
||||||
monsters: STATE.monsters ? STATE.monsters.length : null,
|
monsters: STATE.monsters ? STATE.monsters.length : null,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// CONFIG — default settings
|
// CONFIG — default settings
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
const VERSION = '0.17.1';
|
const VERSION = '0.17.2';
|
||||||
|
|
||||||
const CFG = {
|
const CFG = {
|
||||||
// — Battle strategy advisory
|
// — Battle strategy advisory
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name HV Unified
|
// @name HV Unified
|
||||||
// @namespace hvunified
|
// @namespace hvunified
|
||||||
// @version 0.17.1
|
// @version 0.17.2
|
||||||
// @description HV Unified — Bridge & Strategy/Gear Advisor for HentaiVerse (complements Monsterbation & HVUtils)
|
// @description HV Unified — Bridge & Strategy/Gear Advisor for HentaiVerse (complements Monsterbation & HVUtils)
|
||||||
// @author GaboGG + Hermes
|
// @author GaboGG + Hermes
|
||||||
// @match *://*.hentaiverse.org/*
|
// @match *://*.hentaiverse.org/*
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,29 @@ function jpxPresent() {
|
||||||
document.querySelector('#ctrl-widget, .ctrl-widget'));
|
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).
|
// Trigger jpx's auto-battle toggle (equivalent to pressing M).
|
||||||
// jpx listens for keydown on document (capture phase) and maps key 'm' to
|
// jpx listens for keydown on document (capture phase) and maps key 'm' to
|
||||||
// toggleActive via userKeybinds. A synthetic KeyboardEvent works because
|
// toggleActive via userKeybinds. A synthetic KeyboardEvent works because
|
||||||
|
|
@ -56,20 +79,6 @@ function jpxBattleOver() {
|
||||||
return !jpxMonstersPresent();
|
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
|
// Called when jpx reports a state change via jpx_ctrlWidget_update
|
||||||
function jpxChainOnState(detail) {
|
function jpxChainOnState(detail) {
|
||||||
if (!CFG.autoChainJpx) return;
|
if (!CFG.autoChainJpx) return;
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ window.HV = {
|
||||||
stats: () => JSON.parse(localStorage[SP + 'stats'] || '{"battles":0,"credits":0,"drops":0}'),
|
stats: () => JSON.parse(localStorage[SP + 'stats'] || '{"battles":0,"credits":0,"drops":0}'),
|
||||||
settings: () => toggleSettings(),
|
settings: () => toggleSettings(),
|
||||||
// jpx bridge control
|
// 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; },
|
chain: (on) => { CFG.autoChainJpx = !!on; saveConfig(); if (on) { jpxBridgeWire(); jpxChainStart(); } else { jpxChainStop('manual'); } return 'jpx chain: ' + CFG.autoChainJpx; },
|
||||||
chainState: () => ({ active: jpxChainStarted, rounds: jpxChainRounds, jpx: jpxPresent(), maxRounds: CFG.chainMaxRounds, minHP: CFG.chainMinHP }),
|
chainState: () => ({ active: jpxChainEnabled, rounds: jpxChainRounds, jpx: jpxPresent(), maxRounds: CFG.chainMaxRounds, minHP: CFG.chainMinHP }),
|
||||||
advice: () => {
|
advice: () => {
|
||||||
const s = detectFightingStyle();
|
const s = detectFightingStyle();
|
||||||
return { style: s, attrs: getAttrAdvice(s), spells: getSpellAdvice(), difficulty: getDifficultyAdvice() };
|
return { style: s, attrs: getAttrAdvice(s), spells: getSpellAdvice(), difficulty: getDifficultyAdvice() };
|
||||||
|
|
@ -52,8 +52,16 @@ window.HV = {
|
||||||
document.getElementById('hvut') ||
|
document.getElementById('hvut') ||
|
||||||
window.HVUT ||
|
window.HVUT ||
|
||||||
document.querySelector('[class*="hvut"], [id*="hvut"]')),
|
document.querySelector('[class*="hvut"], [id*="hvut"]')),
|
||||||
|
jpx: jpxPresent(),
|
||||||
unified: true,
|
unified: true,
|
||||||
},
|
},
|
||||||
|
// jpx bridge state
|
||||||
|
jpxBridge: {
|
||||||
|
chainEnabled: jpxChainEnabled,
|
||||||
|
chainRounds: jpxChainRounds,
|
||||||
|
jpxLastActive: jpxLastActive,
|
||||||
|
retryCount: jpxChainRetryCount || 0,
|
||||||
|
},
|
||||||
// State availability
|
// State availability
|
||||||
state_ready: !!STATE && !!STATE.page,
|
state_ready: !!STATE && !!STATE.page,
|
||||||
monsters: STATE.monsters ? STATE.monsters.length : null,
|
monsters: STATE.monsters ? STATE.monsters.length : null,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue