v0.14.27 - Enhanced logging: alive/dead markers, skill readiness, item counts

Log line now shows:
- spBars: 0:29A 1:28A 2:59A 3:52A 4:34A 5:43A 6:29A
  (A=alive onclick, D=dead/no onclick — so you know which SP bars
   are actionable vs leftover from dead mobs)
- sk: RC CC RC (R=Rending Blow Ready/C=Cooldown, S=Shatter, G=Great Cleave)
  — first char of skill name + R/C for ready/cooldown
- h5 s3 m4 (heal=5, spirit=3, mana=4 — item counts per type)
  — so you can see consumable status at a glance
This commit is contained in:
GaboGG 2026-07-28 10:16:31 -04:00
parent ff728fe68f
commit 206c682d9e
5 changed files with 66 additions and 15 deletions

View file

@ -1,7 +1,7 @@
// ==UserScript==
// @name HV Unified
// @namespace hvunified
// @version 0.14.26
// @version 0.14.27
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
// @author GaboGG + Hermes
// @match *://*.hentaiverse.org/*
@ -17,7 +17,7 @@
// CONFIG — default settings
// ═══════════════════════════════════════════════════════════════════════
const VERSION = '0.14.26';
const VERSION = '0.14.27';
const CFG = {
// — Battle automation
@ -1850,17 +1850,34 @@ function setupKeybindings() {
const activeBuffs = Object.entries(STATE.buffs)
.filter(([k, v]) => v > 0 && k !== 'regen' || v > 0)
.map(([k, v]) => `${k}=${v}`).join(' ');
// Monster SP bars (threat levels)
// Monster SP bars (threat levels) with alive/dead markers
const threatLevels = STATE.monsters.map((m, i) => {
const sp = STATE.monsterSp[i] || 0;
return `${i}:${sp}`;
const alive = m && m.hasAttribute && m.hasAttribute('onclick') ? 'A' : 'D';
return `${i}:${sp}${alive}`;
}).join(' ');
// Skill cooldowns — check DOM for opacity/onclick on skill elements
const skillCDs = ['Rending Blow', 'Shatter Strike', 'Great Cleave']
.filter(s => STATE.skillsKnown.includes(s))
.map(s => {
const el = document.querySelector(`.btqs[onmouseover*="set_infopane_spell('${s}'"], .btsd[onmouseover*="set_infopane_spell('${s}'"]`);
const ready = el && el.hasAttribute('onclick');
return `${s.charAt(0)}${ready ? 'R' : 'C'}`;
}).join('');
const curMp = parseInt((document.getElementById('vrm') || {}).textContent) || 0;
const curHp = parseInt((document.getElementById('vrhd') || {}).textContent) || 0;
// Item counts from itemsKnown
const itemTypes = {};
Object.values(STATE.itemsKnown).forEach(info => {
const def = ITEMS[parseInt(info)];
if (def) itemTypes[def.t] = (itemTypes[def.t] || 0) + 1;
});
const itemStr = ['heal','spirit','mana'].filter(t => itemTypes[t]).map(t => `${t.charAt(0)}${itemTypes[t]}`).join(' ');
console.log(
`%c[HV] ch=${STATE.channeling} hp=${curHp} mp=${curMp}(${(STATE.mp*100).toFixed(0)}%) ` +
`sp=${(STATE.sp*100).toFixed(0)}% oc=${STATE.oc.toFixed(0)} ` +
`mon:${STATE.monsters.length} ` +
`mon:${STATE.monsters.length} sk:${skillCDs || '--'} ` +
`${itemStr} ` +
`buffs: ${activeBuffs} | spBars: ${threatLevels}`,
'color:#888'
);

View file

@ -1,7 +1,7 @@
// ==UserScript==
// @name HV Unified
// @namespace hvunified
// @version 0.14.26
// @version 0.14.27
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
// @author GaboGG + Hermes
// @match *://*.hentaiverse.org/*
@ -17,7 +17,7 @@
// CONFIG — default settings
// ═══════════════════════════════════════════════════════════════════════
const VERSION = '0.14.26';
const VERSION = '0.14.27';
const CFG = {
// — Battle automation
@ -1850,17 +1850,34 @@ function setupKeybindings() {
const activeBuffs = Object.entries(STATE.buffs)
.filter(([k, v]) => v > 0 && k !== 'regen' || v > 0)
.map(([k, v]) => `${k}=${v}`).join(' ');
// Monster SP bars (threat levels)
// Monster SP bars (threat levels) with alive/dead markers
const threatLevels = STATE.monsters.map((m, i) => {
const sp = STATE.monsterSp[i] || 0;
return `${i}:${sp}`;
const alive = m && m.hasAttribute && m.hasAttribute('onclick') ? 'A' : 'D';
return `${i}:${sp}${alive}`;
}).join(' ');
// Skill cooldowns — check DOM for opacity/onclick on skill elements
const skillCDs = ['Rending Blow', 'Shatter Strike', 'Great Cleave']
.filter(s => STATE.skillsKnown.includes(s))
.map(s => {
const el = document.querySelector(`.btqs[onmouseover*="set_infopane_spell('${s}'"], .btsd[onmouseover*="set_infopane_spell('${s}'"]`);
const ready = el && el.hasAttribute('onclick');
return `${s.charAt(0)}${ready ? 'R' : 'C'}`;
}).join('');
const curMp = parseInt((document.getElementById('vrm') || {}).textContent) || 0;
const curHp = parseInt((document.getElementById('vrhd') || {}).textContent) || 0;
// Item counts from itemsKnown
const itemTypes = {};
Object.values(STATE.itemsKnown).forEach(info => {
const def = ITEMS[parseInt(info)];
if (def) itemTypes[def.t] = (itemTypes[def.t] || 0) + 1;
});
const itemStr = ['heal','spirit','mana'].filter(t => itemTypes[t]).map(t => `${t.charAt(0)}${itemTypes[t]}`).join(' ');
console.log(
`%c[HV] ch=${STATE.channeling} hp=${curHp} mp=${curMp}(${(STATE.mp*100).toFixed(0)}%) ` +
`sp=${(STATE.sp*100).toFixed(0)}% oc=${STATE.oc.toFixed(0)} ` +
`mon:${STATE.monsters.length} ` +
`mon:${STATE.monsters.length} sk:${skillCDs || '--'} ` +
`${itemStr} ` +
`buffs: ${activeBuffs} | spBars: ${threatLevels}`,
'color:#888'
);

View file

@ -2,7 +2,7 @@
// CONFIG — default settings
// ═══════════════════════════════════════════════════════════════════════
const VERSION = '0.14.26';
const VERSION = '0.14.27';
const CFG = {
// — Battle automation

View file

@ -1,7 +1,7 @@
// ==UserScript==
// @name HV Unified
// @namespace hvunified
// @version 0.14.26
// @version 0.14.27
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
// @author GaboGG + Hermes
// @match *://*.hentaiverse.org/*

View file

@ -34,17 +34,34 @@ function setupKeybindings() {
const activeBuffs = Object.entries(STATE.buffs)
.filter(([k, v]) => v > 0 && k !== 'regen' || v > 0)
.map(([k, v]) => `${k}=${v}`).join(' ');
// Monster SP bars (threat levels)
// Monster SP bars (threat levels) with alive/dead markers
const threatLevels = STATE.monsters.map((m, i) => {
const sp = STATE.monsterSp[i] || 0;
return `${i}:${sp}`;
const alive = m && m.hasAttribute && m.hasAttribute('onclick') ? 'A' : 'D';
return `${i}:${sp}${alive}`;
}).join(' ');
// Skill cooldowns — check DOM for opacity/onclick on skill elements
const skillCDs = ['Rending Blow', 'Shatter Strike', 'Great Cleave']
.filter(s => STATE.skillsKnown.includes(s))
.map(s => {
const el = document.querySelector(`.btqs[onmouseover*="set_infopane_spell('${s}'"], .btsd[onmouseover*="set_infopane_spell('${s}'"]`);
const ready = el && el.hasAttribute('onclick');
return `${s.charAt(0)}${ready ? 'R' : 'C'}`;
}).join('');
const curMp = parseInt((document.getElementById('vrm') || {}).textContent) || 0;
const curHp = parseInt((document.getElementById('vrhd') || {}).textContent) || 0;
// Item counts from itemsKnown
const itemTypes = {};
Object.values(STATE.itemsKnown).forEach(info => {
const def = ITEMS[parseInt(info)];
if (def) itemTypes[def.t] = (itemTypes[def.t] || 0) + 1;
});
const itemStr = ['heal','spirit','mana'].filter(t => itemTypes[t]).map(t => `${t.charAt(0)}${itemTypes[t]}`).join(' ');
console.log(
`%c[HV] ch=${STATE.channeling} hp=${curHp} mp=${curMp}(${(STATE.mp*100).toFixed(0)}%) ` +
`sp=${(STATE.sp*100).toFixed(0)}% oc=${STATE.oc.toFixed(0)} ` +
`mon:${STATE.monsters.length} ` +
`mon:${STATE.monsters.length} sk:${skillCDs || '--'} ` +
`${itemStr} ` +
`buffs: ${activeBuffs} | spBars: ${threatLevels}`,
'color:#888'
);