v0.15.3 - Scorer now accounts for weapon damage, elemental damage, and procs
Parser fix: parseEquipHTML now captures the direct-child divs of the
tooltip that were previously skipped:
- Proc lines: 'Penetrated Armor: 21.7% chance' -> stats['Proc Penetrated Armor']
- Base damage: '+708 Piercing Damage' -> stats['Weapon Damage']
- Elemental lines: '+25 Fire Damage' / '+30 Elec Strike' -> stats['Elemental Fire']
Scorer (gearScoreWeapon + analyze_gear.py):
- Weapon Damage x 0.30 (base damage matters)
- Elemental damage x 0.25 per element
- Proc bonuses by type: CC procs (stun/freeze) x0.45, armor break
x0.35, DoT x0.25, generic x0.15
- All multiplied by the same quality multiplier afterward
So an elemental weapon with a strike proc now gets its due — the
short-margin stat winner may no longer win once damage+proc count.
Note: re-scrape the armory/store after updating so the new fields
get captured (old entries lack Weapon Damage/Proc keys).
This commit is contained in:
parent
b069d42fc8
commit
f993014a46
7 changed files with 182 additions and 6 deletions
|
|
@ -67,6 +67,20 @@ def score_weapon(item):
|
|||
s += get_num(stats.get('Block',0)) * 0.5
|
||||
s += get_num(stats.get('Agility',0)) * 0.5
|
||||
s -= get_num(stats.get('burden',0)) * 0.5
|
||||
# Base weapon damage + elemental damage
|
||||
s += get_num(stats.get('Weapon Damage',0)) * 0.30
|
||||
for el in ['Fire','Cold','Elec','Wind','Holy','Dark','Ethereal','Elemental']:
|
||||
s += get_num(stats.get('Elemental ' + el,0)) * 0.25
|
||||
# Proc lines
|
||||
for k, v in stats.items():
|
||||
if k.startswith('Proc '):
|
||||
pct = get_num(v)
|
||||
pname = k.replace('Proc ','').lower()
|
||||
if 'penetrated armor' in pname or 'armor' in pname: s += pct * 0.35
|
||||
elif any(x in pname for x in ['stun','freeze','slow','paraly']): s += pct * 0.45
|
||||
elif any(x in pname for x in ['bleeding','wound','poison','burn','shock']): s += pct * 0.25
|
||||
elif 'weaken' in pname or 'impair' in pname: s += pct * 0.25
|
||||
else: s += pct * 0.15
|
||||
|
||||
# Quality multiplier: higher tiers have better base damage
|
||||
# q6=Magnificent, q5=Exquisite, q4=Superior, q3=Average, q2=Fair, q1=Crude
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name HV Unified
|
||||
// @namespace hvunified
|
||||
// @version 0.15.2
|
||||
// @version 0.15.3
|
||||
// @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.15.2';
|
||||
const VERSION = '0.15.3';
|
||||
|
||||
const CFG = {
|
||||
// — Battle automation
|
||||
|
|
@ -3512,6 +3512,41 @@ function parseEquipHTML(htmlStr) {
|
|||
const ex = eq.querySelector('.ex');
|
||||
if (ex) ex.querySelectorAll(':scope > div').forEach(parseRow);
|
||||
|
||||
// Direct-child rows of .eq — weapon damage + proc lines.
|
||||
// e.g. <div><span>Penetrated Armor</span>: <span>21.7% chance</span></div>
|
||||
// <div title="Base: 134">+<span>708 Piercing Damage</span></div>
|
||||
Array.from(eq.children).forEach(child => {
|
||||
if (child.classList && (child.classList.contains('eqt') || child.classList.contains('eqr')
|
||||
|| child.classList.contains('eqc') || child.classList.contains('ex') || child.classList.contains('ep'))) return;
|
||||
const text = (child.textContent || '').trim();
|
||||
if (!text) return;
|
||||
|
||||
// Proc line: "Name: 21.7% chance"
|
||||
const procM = text.match(/^([A-Za-z][A-Za-z ]+):\s*([\d.]+%?\s*(?:chance|procs?)?)/);
|
||||
if (procM && child.querySelector('span')) {
|
||||
stats['Proc ' + procM[1].trim()] = procM[2].trim();
|
||||
return;
|
||||
}
|
||||
|
||||
// Weapon damage line: "+708 Piercing Damage"
|
||||
const dmgM = text.match(/^\+([\d,]+)\s*([A-Za-z]+)\s*Damage$/);
|
||||
if (dmgM) {
|
||||
stats['Weapon Damage'] = parseInt(dmgM[1].replace(/,/g, ''));
|
||||
stats['Damage Type'] = dmgM[2];
|
||||
const title = child.getAttribute('title') || '';
|
||||
const baseM = title.match(/Base:\s*(\d+)/i);
|
||||
if (baseM) stats['Weapon Damage Base'] = parseInt(baseM[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Elemental damage lines: "+25 Fire Damage" or "+30 Elec Damage"
|
||||
const elemM = text.match(/^\+([\d,]+)\s*(Fire|Cold|Elec|Wind|Holy|Dark|Ethereal|Elemental)\s*(?:Damage|Strike)$/);
|
||||
if (elemM) {
|
||||
stats['Elemental ' + elemM[2]] = parseInt(elemM[1].replace(/,/g, ''));
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// Extra stat groups (.ep)
|
||||
eq.querySelectorAll('.ep').forEach(g => {
|
||||
g.querySelectorAll(':scope > div:not(:first-child)').forEach(parseRow);
|
||||
|
|
@ -3829,6 +3864,25 @@ function gearScoreWeapon(item) {
|
|||
s += _num(st['Block']) * 0.5;
|
||||
s += _num(st['Agility']) * 0.5;
|
||||
s -= _num(st['burden']) * 0.5;
|
||||
// Base weapon damage (e.g. "+708 Piercing Damage") — scales with quality
|
||||
s += _num(st['Weapon Damage']) * 0.30;
|
||||
// Elemental damage lines (e.g. "+25 Fire Damage", "+30 Elec Strike")
|
||||
['Fire', 'Cold', 'Elec', 'Wind', 'Holy', 'Dark', 'Ethereal', 'Elemental'].forEach(el => {
|
||||
s += _num(st['Elemental ' + el]) * 0.25;
|
||||
});
|
||||
// Proc lines: elemental/status procs add value (e.g. "Proc Penetrated Armor: 21.7%")
|
||||
let procBonus = 0;
|
||||
Object.keys(st).forEach(k => {
|
||||
if (!k.startsWith('Proc ')) return;
|
||||
const pct = _num(st[k]);
|
||||
const pname = k.replace('Proc ', '').toLowerCase();
|
||||
if (pname.includes('penetrated armor') || pname.includes('armor')) procBonus += pct * 0.35;
|
||||
else if (pname.includes('stun') || pname.includes('freeze') || pname.includes('slow') || pname.includes('paraly')) procBonus += pct * 0.45;
|
||||
else if (pname.includes('bleeding') || pname.includes('wound') || pname.includes('poison') || pname.includes('burn') || pname.includes('shock')) procBonus += pct * 0.25;
|
||||
else if (pname.includes('weaken') || pname.includes('impair')) procBonus += pct * 0.25;
|
||||
else procBonus += pct * 0.15; // generic proc value
|
||||
});
|
||||
s += procBonus;
|
||||
// Quality multiplier (q6=Magnificent, q5=Exquisite, q4=Superior)
|
||||
s *= 0.8 + (quality * 0.12);
|
||||
// Weapon type bonus
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name HV Unified
|
||||
// @namespace hvunified
|
||||
// @version 0.15.2
|
||||
// @version 0.15.3
|
||||
// @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.15.2';
|
||||
const VERSION = '0.15.3';
|
||||
|
||||
const CFG = {
|
||||
// — Battle automation
|
||||
|
|
@ -3512,6 +3512,41 @@ function parseEquipHTML(htmlStr) {
|
|||
const ex = eq.querySelector('.ex');
|
||||
if (ex) ex.querySelectorAll(':scope > div').forEach(parseRow);
|
||||
|
||||
// Direct-child rows of .eq — weapon damage + proc lines.
|
||||
// e.g. <div><span>Penetrated Armor</span>: <span>21.7% chance</span></div>
|
||||
// <div title="Base: 134">+<span>708 Piercing Damage</span></div>
|
||||
Array.from(eq.children).forEach(child => {
|
||||
if (child.classList && (child.classList.contains('eqt') || child.classList.contains('eqr')
|
||||
|| child.classList.contains('eqc') || child.classList.contains('ex') || child.classList.contains('ep'))) return;
|
||||
const text = (child.textContent || '').trim();
|
||||
if (!text) return;
|
||||
|
||||
// Proc line: "Name: 21.7% chance"
|
||||
const procM = text.match(/^([A-Za-z][A-Za-z ]+):\s*([\d.]+%?\s*(?:chance|procs?)?)/);
|
||||
if (procM && child.querySelector('span')) {
|
||||
stats['Proc ' + procM[1].trim()] = procM[2].trim();
|
||||
return;
|
||||
}
|
||||
|
||||
// Weapon damage line: "+708 Piercing Damage"
|
||||
const dmgM = text.match(/^\+([\d,]+)\s*([A-Za-z]+)\s*Damage$/);
|
||||
if (dmgM) {
|
||||
stats['Weapon Damage'] = parseInt(dmgM[1].replace(/,/g, ''));
|
||||
stats['Damage Type'] = dmgM[2];
|
||||
const title = child.getAttribute('title') || '';
|
||||
const baseM = title.match(/Base:\s*(\d+)/i);
|
||||
if (baseM) stats['Weapon Damage Base'] = parseInt(baseM[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Elemental damage lines: "+25 Fire Damage" or "+30 Elec Damage"
|
||||
const elemM = text.match(/^\+([\d,]+)\s*(Fire|Cold|Elec|Wind|Holy|Dark|Ethereal|Elemental)\s*(?:Damage|Strike)$/);
|
||||
if (elemM) {
|
||||
stats['Elemental ' + elemM[2]] = parseInt(elemM[1].replace(/,/g, ''));
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// Extra stat groups (.ep)
|
||||
eq.querySelectorAll('.ep').forEach(g => {
|
||||
g.querySelectorAll(':scope > div:not(:first-child)').forEach(parseRow);
|
||||
|
|
@ -3829,6 +3864,25 @@ function gearScoreWeapon(item) {
|
|||
s += _num(st['Block']) * 0.5;
|
||||
s += _num(st['Agility']) * 0.5;
|
||||
s -= _num(st['burden']) * 0.5;
|
||||
// Base weapon damage (e.g. "+708 Piercing Damage") — scales with quality
|
||||
s += _num(st['Weapon Damage']) * 0.30;
|
||||
// Elemental damage lines (e.g. "+25 Fire Damage", "+30 Elec Strike")
|
||||
['Fire', 'Cold', 'Elec', 'Wind', 'Holy', 'Dark', 'Ethereal', 'Elemental'].forEach(el => {
|
||||
s += _num(st['Elemental ' + el]) * 0.25;
|
||||
});
|
||||
// Proc lines: elemental/status procs add value (e.g. "Proc Penetrated Armor: 21.7%")
|
||||
let procBonus = 0;
|
||||
Object.keys(st).forEach(k => {
|
||||
if (!k.startsWith('Proc ')) return;
|
||||
const pct = _num(st[k]);
|
||||
const pname = k.replace('Proc ', '').toLowerCase();
|
||||
if (pname.includes('penetrated armor') || pname.includes('armor')) procBonus += pct * 0.35;
|
||||
else if (pname.includes('stun') || pname.includes('freeze') || pname.includes('slow') || pname.includes('paraly')) procBonus += pct * 0.45;
|
||||
else if (pname.includes('bleeding') || pname.includes('wound') || pname.includes('poison') || pname.includes('burn') || pname.includes('shock')) procBonus += pct * 0.25;
|
||||
else if (pname.includes('weaken') || pname.includes('impair')) procBonus += pct * 0.25;
|
||||
else procBonus += pct * 0.15; // generic proc value
|
||||
});
|
||||
s += procBonus;
|
||||
// Quality multiplier (q6=Magnificent, q5=Exquisite, q4=Superior)
|
||||
s *= 0.8 + (quality * 0.12);
|
||||
// Weapon type bonus
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// CONFIG — default settings
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
const VERSION = '0.15.2';
|
||||
const VERSION = '0.15.3';
|
||||
|
||||
const CFG = {
|
||||
// — Battle automation
|
||||
|
|
|
|||
|
|
@ -45,6 +45,25 @@ function gearScoreWeapon(item) {
|
|||
s += _num(st['Block']) * 0.5;
|
||||
s += _num(st['Agility']) * 0.5;
|
||||
s -= _num(st['burden']) * 0.5;
|
||||
// Base weapon damage (e.g. "+708 Piercing Damage") — scales with quality
|
||||
s += _num(st['Weapon Damage']) * 0.30;
|
||||
// Elemental damage lines (e.g. "+25 Fire Damage", "+30 Elec Strike")
|
||||
['Fire', 'Cold', 'Elec', 'Wind', 'Holy', 'Dark', 'Ethereal', 'Elemental'].forEach(el => {
|
||||
s += _num(st['Elemental ' + el]) * 0.25;
|
||||
});
|
||||
// Proc lines: elemental/status procs add value (e.g. "Proc Penetrated Armor: 21.7%")
|
||||
let procBonus = 0;
|
||||
Object.keys(st).forEach(k => {
|
||||
if (!k.startsWith('Proc ')) return;
|
||||
const pct = _num(st[k]);
|
||||
const pname = k.replace('Proc ', '').toLowerCase();
|
||||
if (pname.includes('penetrated armor') || pname.includes('armor')) procBonus += pct * 0.35;
|
||||
else if (pname.includes('stun') || pname.includes('freeze') || pname.includes('slow') || pname.includes('paraly')) procBonus += pct * 0.45;
|
||||
else if (pname.includes('bleeding') || pname.includes('wound') || pname.includes('poison') || pname.includes('burn') || pname.includes('shock')) procBonus += pct * 0.25;
|
||||
else if (pname.includes('weaken') || pname.includes('impair')) procBonus += pct * 0.25;
|
||||
else procBonus += pct * 0.15; // generic proc value
|
||||
});
|
||||
s += procBonus;
|
||||
// Quality multiplier (q6=Magnificent, q5=Exquisite, q4=Superior)
|
||||
s *= 0.8 + (quality * 0.12);
|
||||
// Weapon type bonus
|
||||
|
|
|
|||
|
|
@ -117,6 +117,41 @@ function parseEquipHTML(htmlStr) {
|
|||
const ex = eq.querySelector('.ex');
|
||||
if (ex) ex.querySelectorAll(':scope > div').forEach(parseRow);
|
||||
|
||||
// Direct-child rows of .eq — weapon damage + proc lines.
|
||||
// e.g. <div><span>Penetrated Armor</span>: <span>21.7% chance</span></div>
|
||||
// <div title="Base: 134">+<span>708 Piercing Damage</span></div>
|
||||
Array.from(eq.children).forEach(child => {
|
||||
if (child.classList && (child.classList.contains('eqt') || child.classList.contains('eqr')
|
||||
|| child.classList.contains('eqc') || child.classList.contains('ex') || child.classList.contains('ep'))) return;
|
||||
const text = (child.textContent || '').trim();
|
||||
if (!text) return;
|
||||
|
||||
// Proc line: "Name: 21.7% chance"
|
||||
const procM = text.match(/^([A-Za-z][A-Za-z ]+):\s*([\d.]+%?\s*(?:chance|procs?)?)/);
|
||||
if (procM && child.querySelector('span')) {
|
||||
stats['Proc ' + procM[1].trim()] = procM[2].trim();
|
||||
return;
|
||||
}
|
||||
|
||||
// Weapon damage line: "+708 Piercing Damage"
|
||||
const dmgM = text.match(/^\+([\d,]+)\s*([A-Za-z]+)\s*Damage$/);
|
||||
if (dmgM) {
|
||||
stats['Weapon Damage'] = parseInt(dmgM[1].replace(/,/g, ''));
|
||||
stats['Damage Type'] = dmgM[2];
|
||||
const title = child.getAttribute('title') || '';
|
||||
const baseM = title.match(/Base:\s*(\d+)/i);
|
||||
if (baseM) stats['Weapon Damage Base'] = parseInt(baseM[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Elemental damage lines: "+25 Fire Damage" or "+30 Elec Damage"
|
||||
const elemM = text.match(/^\+([\d,]+)\s*(Fire|Cold|Elec|Wind|Holy|Dark|Ethereal|Elemental)\s*(?:Damage|Strike)$/);
|
||||
if (elemM) {
|
||||
stats['Elemental ' + elemM[2]] = parseInt(elemM[1].replace(/,/g, ''));
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// Extra stat groups (.ep)
|
||||
eq.querySelectorAll('.ep').forEach(g => {
|
||||
g.querySelectorAll(':scope > div:not(:first-child)').forEach(parseRow);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name HV Unified
|
||||
// @namespace hvunified
|
||||
// @version 0.15.2
|
||||
// @version 0.15.3
|
||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||
// @author GaboGG + Hermes
|
||||
// @match *://*.hentaiverse.org/*
|
||||
|
|
|
|||
Loading…
Reference in a new issue