v0.17.6 - jpx chain: never press M while jpx is active (toggle-off guard)

Fixes the race where our synthetic M landed while jpx was mid-round
(active=true) and disabled the chain. Now jpxTriggerAuto skips if
jpxLastActive===true, and the initial press waits for jpx's first state
event. NOTE: ajaxRound must stay OFF for chaining to work — jpx's AJAX
round advance dispatches a synthetic DOMContentLoaded that resets its
own isActiveBattle flag.
This commit is contained in:
GaboGG 2026-08-04 17:15:42 -04:00
parent 5012d5f74f
commit 751d001ba3
5 changed files with 66 additions and 27 deletions

View file

@ -1,7 +1,7 @@
// ==UserScript==
// @name HV Unified
// @namespace hvunified
// @version 0.17.5
// @version 0.17.6
// @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.5';
const VERSION = '0.17.6';
const CFG = {
// — Battle strategy advisory
@ -1587,16 +1587,30 @@ function jpxChainStart() {
jpxChainEnabled = true;
jpxChainRounds = 0;
jpxChainCooldown = Date.now();
// Start the first auto round (equivalent to pressing M once)
setTimeout(jpxTriggerAuto, 800);
// Start the first auto round — but only AFTER we know jpx's real state
// (wait up to 1.5s for its first jpx_ctrlWidget_update event). If the
// user already pressed M manually, jpxLastActive=true and we skip.
let waited = 0;
const sync = setInterval(() => {
waited += 300;
if (jpxLastActive !== null || waited > 1500) {
clearInterval(sync);
setTimeout(jpxTriggerAuto, 200);
}
}, 300);
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
// jpx reads e.key, not e.isTrusted.
// Trigger jpx's auto-battle (equivalent to pressing M) — ONLY when jpx is
// currently INACTIVE. Pressing M while jpx is already active toggles it OFF,
// which is the bug we hit: our M landed while jpx was mid-round (active=true)
// and disabled the chain.
function jpxTriggerAuto() {
// If we know jpx is already active, pressing M would DISABLE it — skip.
if (jpxLastActive === true) {
console.log('%c[HV] ⛓ jpx already active — skipping M (would toggle off)', 'color:#f80');
return false;
}
try {
const evt = new KeyboardEvent('keydown', {
key: 'm',
@ -1607,7 +1621,6 @@ function jpxTriggerAuto() {
cancelable: true,
});
// Give jpx a moment to process, then verify via its own state event.
// If it didn't toggle, the keybind didn't reach jpx.
const before = jpxLastActive;
document.dispatchEvent(evt);
setTimeout(() => {

View file

@ -1,7 +1,7 @@
// ==UserScript==
// @name HV Unified
// @namespace hvunified
// @version 0.17.5
// @version 0.17.6
// @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.5';
const VERSION = '0.17.6';
const CFG = {
// — Battle strategy advisory
@ -1587,16 +1587,30 @@ function jpxChainStart() {
jpxChainEnabled = true;
jpxChainRounds = 0;
jpxChainCooldown = Date.now();
// Start the first auto round (equivalent to pressing M once)
setTimeout(jpxTriggerAuto, 800);
// Start the first auto round — but only AFTER we know jpx's real state
// (wait up to 1.5s for its first jpx_ctrlWidget_update event). If the
// user already pressed M manually, jpxLastActive=true and we skip.
let waited = 0;
const sync = setInterval(() => {
waited += 300;
if (jpxLastActive !== null || waited > 1500) {
clearInterval(sync);
setTimeout(jpxTriggerAuto, 200);
}
}, 300);
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
// jpx reads e.key, not e.isTrusted.
// Trigger jpx's auto-battle (equivalent to pressing M) — ONLY when jpx is
// currently INACTIVE. Pressing M while jpx is already active toggles it OFF,
// which is the bug we hit: our M landed while jpx was mid-round (active=true)
// and disabled the chain.
function jpxTriggerAuto() {
// If we know jpx is already active, pressing M would DISABLE it — skip.
if (jpxLastActive === true) {
console.log('%c[HV] ⛓ jpx already active — skipping M (would toggle off)', 'color:#f80');
return false;
}
try {
const evt = new KeyboardEvent('keydown', {
key: 'm',
@ -1607,7 +1621,6 @@ function jpxTriggerAuto() {
cancelable: true,
});
// Give jpx a moment to process, then verify via its own state event.
// If it didn't toggle, the keybind didn't reach jpx.
const before = jpxLastActive;
document.dispatchEvent(evt);
setTimeout(() => {

View file

@ -2,7 +2,7 @@
// CONFIG — default settings
// ═══════════════════════════════════════════════════════════════════════
const VERSION = '0.17.5';
const VERSION = '0.17.6';
const CFG = {
// — Battle strategy advisory

View file

@ -1,7 +1,7 @@
// ==UserScript==
// @name HV Unified
// @namespace hvunified
// @version 0.17.5
// @version 0.17.6
// @description HV Unified — Bridge & Strategy/Gear Advisor for HentaiVerse (complements Monsterbation & HVUtils)
// @author GaboGG + Hermes
// @match *://*.hentaiverse.org/*

View file

@ -40,16 +40,30 @@ function jpxChainStart() {
jpxChainEnabled = true;
jpxChainRounds = 0;
jpxChainCooldown = Date.now();
// Start the first auto round (equivalent to pressing M once)
setTimeout(jpxTriggerAuto, 800);
// Start the first auto round — but only AFTER we know jpx's real state
// (wait up to 1.5s for its first jpx_ctrlWidget_update event). If the
// user already pressed M manually, jpxLastActive=true and we skip.
let waited = 0;
const sync = setInterval(() => {
waited += 300;
if (jpxLastActive !== null || waited > 1500) {
clearInterval(sync);
setTimeout(jpxTriggerAuto, 200);
}
}, 300);
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
// jpx reads e.key, not e.isTrusted.
// Trigger jpx's auto-battle (equivalent to pressing M) — ONLY when jpx is
// currently INACTIVE. Pressing M while jpx is already active toggles it OFF,
// which is the bug we hit: our M landed while jpx was mid-round (active=true)
// and disabled the chain.
function jpxTriggerAuto() {
// If we know jpx is already active, pressing M would DISABLE it — skip.
if (jpxLastActive === true) {
console.log('%c[HV] ⛓ jpx already active — skipping M (would toggle off)', 'color:#f80');
return false;
}
try {
const evt = new KeyboardEvent('keydown', {
key: 'm',
@ -60,7 +74,6 @@ function jpxTriggerAuto() {
cancelable: true,
});
// Give jpx a moment to process, then verify via its own state event.
// If it didn't toggle, the keybind didn't reach jpx.
const before = jpxLastActive;
document.dispatchEvent(evt);
setTimeout(() => {