diff --git a/analyze_gear.py b/analyze_gear.py index 8be472b..c358406 100644 --- a/analyze_gear.py +++ b/analyze_gear.py @@ -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 diff --git a/scripts/hv-unified.user.js b/scripts/hv-unified.user.js index 3abd29f..a9a43b8 100644 --- a/scripts/hv-unified.user.js +++ b/scripts/hv-unified.user.js @@ -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.
Penetrated Armor: 21.7% chance
+ //
+708 Piercing Damage
+ 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 diff --git a/scripts/latest.user.js b/scripts/latest.user.js index 3abd29f..a9a43b8 100644 --- a/scripts/latest.user.js +++ b/scripts/latest.user.js @@ -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.
Penetrated Armor: 21.7% chance
+ //
+708 Piercing Damage
+ 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 diff --git a/src/config.js b/src/config.js index aeb9668..f985738 100644 --- a/src/config.js +++ b/src/config.js @@ -2,7 +2,7 @@ // CONFIG — default settings // ═══════════════════════════════════════════════════════════════════════ -const VERSION = '0.15.2'; +const VERSION = '0.15.3'; const CFG = { // — Battle automation diff --git a/src/gear-analysis.js b/src/gear-analysis.js index 913f298..70fbd1e 100644 --- a/src/gear-analysis.js +++ b/src/gear-analysis.js @@ -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 diff --git a/src/gear-scraper.js b/src/gear-scraper.js index 83b9f37..fbf82cc 100644 --- a/src/gear-scraper.js +++ b/src/gear-scraper.js @@ -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.
Penetrated Armor: 21.7% chance
+ //
+708 Piercing Damage
+ 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); diff --git a/src/header.user.js b/src/header.user.js index 325ec74..21e8bce 100644 --- a/src/header.user.js +++ b/src/header.user.js @@ -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/*