v0.15.4 - Elemental Strikes parsed + scored per wiki (Void Strike, etc.)
From EHWiki Detailed_Equip_Characteristics + Equipment_Basics: - Elemental strikes are 'X Strike (Y%)' lines (Void/Fire/Cold/Elec/ Wind/Holy/Dark), separate hit for ~50% of physical damage, max 2 strikes + Void Strike - Ethereal weapons deal Void damage (+523 Void Damage), prefixes: Ethereal→Void, Fiery→Fire, Arctic→Cold, Shocking→Elec, Tempestuous→Wind, Hallowed→Holy, Demonic→Dark - Weapon procs by type: Piercing→Penetrated Armor (Estoc/Rapier), Crushing→Stun (Mace/Club), Slashing→Bleeding Wound (Longsword/ Katana/Shortsword/Axe/Wakizashi) Parser now captures: - stats['Strike <Elem>'] = chance% (e.g. 'Strike Void': 50) - stats['Weapon Damage'] for Void too (+523 Void Damage) Scorer adds expected strike damage (chance/100 × 0.5 × weapon dmg) weighted same as base damage. Type bonuses updated to match real procs (Stun 1.15x > Bleeding 1.10x, Rapier 1.20x like Estoc 1.25x). So your lottery Peerless Ethereal Rapier (+523 Void, Void Strike 50%) now scores properly. Note: re-scrape after update for Strike fields.
This commit is contained in:
parent
f993014a46
commit
589ed7e34c
7 changed files with 101 additions and 54 deletions
|
|
@ -67,10 +67,14 @@ def score_weapon(item):
|
||||||
s += get_num(stats.get('Block',0)) * 0.5
|
s += get_num(stats.get('Block',0)) * 0.5
|
||||||
s += get_num(stats.get('Agility',0)) * 0.5
|
s += get_num(stats.get('Agility',0)) * 0.5
|
||||||
s -= get_num(stats.get('burden',0)) * 0.5
|
s -= get_num(stats.get('burden',0)) * 0.5
|
||||||
# Base weapon damage + elemental damage
|
# Base weapon damage + elemental strikes
|
||||||
s += get_num(stats.get('Weapon Damage',0)) * 0.30
|
wd = get_num(stats.get('Weapon Damage',0))
|
||||||
for el in ['Fire','Cold','Elec','Wind','Holy','Dark','Ethereal','Elemental']:
|
s += wd * 0.30
|
||||||
s += get_num(stats.get('Elemental ' + el,0)) * 0.25
|
for el in ['Fire','Cold','Elec','Wind','Holy','Dark','Void','Ethereal']:
|
||||||
|
chance = get_num(stats.get('Strike ' + el,0))
|
||||||
|
if chance > 0:
|
||||||
|
expected = (chance / 100) * 0.5 * wd
|
||||||
|
s += expected * 0.30 if expected > 0 else chance * 0.15
|
||||||
# Proc lines
|
# Proc lines
|
||||||
for k, v in stats.items():
|
for k, v in stats.items():
|
||||||
if k.startswith('Proc '):
|
if k.startswith('Proc '):
|
||||||
|
|
@ -87,18 +91,16 @@ def score_weapon(item):
|
||||||
quality_mult = 0.8 + (quality * 0.12) # q4=1.28x, q5=1.40x, q6=1.52x
|
quality_mult = 0.8 + (quality * 0.12) # q4=1.28x, q5=1.40x, q6=1.52x
|
||||||
s *= quality_mult
|
s *= quality_mult
|
||||||
|
|
||||||
# Weapon type bonus: Estoc has Penetrated Armor proc (armor break)
|
# Weapon type bonus (wiki procs: Piercing→Penetrated Armor, Crushing→Stun,
|
||||||
# Longsword has Weaken proc (damage debuff on enemies)
|
# Slashing→Bleeding Wound; Estoc=2H Penetrated Armor is the 2H physical build's core)
|
||||||
if 'estoc' in name_lower:
|
if 'estoc' in name_lower:
|
||||||
s *= 1.25 # Estoc's Penetrated Armor is the defining proc for 2H physical builds
|
s *= 1.25
|
||||||
elif 'longsword' in name_lower:
|
elif 'rapier' in name_lower:
|
||||||
s *= 1.10 # Weaken proc is decent but not as impactful
|
s *= 1.20 # 1H Penetrated Armor
|
||||||
elif 'great mace' in name_lower:
|
elif any(k in name_lower for k in ['longsword','katana','shortsword','axe','wakizashi']):
|
||||||
s *= 0.90 # No armor pen, lower utility
|
s *= 1.10 # Bleeding Wound
|
||||||
elif 'club' in name_lower:
|
elif any(k in name_lower for k in ['great mace','club','mace']):
|
||||||
s *= 0.85
|
s *= 1.15 # Stun
|
||||||
elif 'axe' in name_lower:
|
|
||||||
s *= 0.90
|
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name HV Unified
|
// @name HV Unified
|
||||||
// @namespace hvunified
|
// @namespace hvunified
|
||||||
// @version 0.15.3
|
// @version 0.15.4
|
||||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||||
// @author GaboGG + Hermes
|
// @author GaboGG + Hermes
|
||||||
// @match *://*.hentaiverse.org/*
|
// @match *://*.hentaiverse.org/*
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
// CONFIG — default settings
|
// CONFIG — default settings
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
const VERSION = '0.15.3';
|
const VERSION = '0.15.4';
|
||||||
|
|
||||||
const CFG = {
|
const CFG = {
|
||||||
// — Battle automation
|
// — Battle automation
|
||||||
|
|
@ -3528,7 +3528,16 @@ function parseEquipHTML(htmlStr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weapon damage line: "+708 Piercing Damage"
|
// Elemental Strike line (wiki: "X Strike (Y%)" — e.g. "Void Strike (50%)")
|
||||||
|
// Additional ~50%-of-physical-damage hit; max 2 strikes + Void Strike.
|
||||||
|
const strikeM = text.match(/^([A-Za-z]+)\s+Strike\s*\(\s*(\d+)%\s*\)$/);
|
||||||
|
if (strikeM) {
|
||||||
|
stats['Strike ' + strikeM[1]] = parseInt(strikeM[2]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Weapon damage line: "+523 Void Damage" / "+708 Piercing Damage"
|
||||||
|
// Base type can be Slashing/Crushing/Piercing, or Void for Ethereal.
|
||||||
const dmgM = text.match(/^\+([\d,]+)\s*([A-Za-z]+)\s*Damage$/);
|
const dmgM = text.match(/^\+([\d,]+)\s*([A-Za-z]+)\s*Damage$/);
|
||||||
if (dmgM) {
|
if (dmgM) {
|
||||||
stats['Weapon Damage'] = parseInt(dmgM[1].replace(/,/g, ''));
|
stats['Weapon Damage'] = parseInt(dmgM[1].replace(/,/g, ''));
|
||||||
|
|
@ -3864,11 +3873,17 @@ function gearScoreWeapon(item) {
|
||||||
s += _num(st['Block']) * 0.5;
|
s += _num(st['Block']) * 0.5;
|
||||||
s += _num(st['Agility']) * 0.5;
|
s += _num(st['Agility']) * 0.5;
|
||||||
s -= _num(st['burden']) * 0.5;
|
s -= _num(st['burden']) * 0.5;
|
||||||
// Base weapon damage (e.g. "+708 Piercing Damage") — scales with quality
|
// Base weapon damage (e.g. "+708 Piercing Damage", "+523 Void Damage") — scales with quality
|
||||||
s += _num(st['Weapon Damage']) * 0.30;
|
const wd = _num(st['Weapon Damage']);
|
||||||
// Elemental damage lines (e.g. "+25 Fire Damage", "+30 Elec Strike")
|
s += wd * 0.30;
|
||||||
['Fire', 'Cold', 'Elec', 'Wind', 'Holy', 'Dark', 'Ethereal', 'Elemental'].forEach(el => {
|
// Elemental Strikes (wiki: "X Strike (Y%)" — separate hit for ~50% of physical damage)
|
||||||
s += _num(st['Elemental ' + el]) * 0.25;
|
// Expected damage = chance% × 0.5 × weapon damage. Weight same as base damage (0.30).
|
||||||
|
['Fire', 'Cold', 'Elec', 'Wind', 'Holy', 'Dark', 'Void', 'Ethereal'].forEach(el => {
|
||||||
|
const chance = _num(st['Strike ' + el]);
|
||||||
|
if (chance > 0) {
|
||||||
|
const expected = (chance / 100) * 0.5 * wd;
|
||||||
|
s += expected > 0 ? expected * 0.30 : chance * 0.15;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// Proc lines: elemental/status procs add value (e.g. "Proc Penetrated Armor: 21.7%")
|
// Proc lines: elemental/status procs add value (e.g. "Proc Penetrated Armor: 21.7%")
|
||||||
let procBonus = 0;
|
let procBonus = 0;
|
||||||
|
|
@ -3885,12 +3900,12 @@ function gearScoreWeapon(item) {
|
||||||
s += procBonus;
|
s += procBonus;
|
||||||
// Quality multiplier (q6=Magnificent, q5=Exquisite, q4=Superior)
|
// Quality multiplier (q6=Magnificent, q5=Exquisite, q4=Superior)
|
||||||
s *= 0.8 + (quality * 0.12);
|
s *= 0.8 + (quality * 0.12);
|
||||||
// Weapon type bonus
|
// Weapon type bonus (wiki procs: Piercing→Penetrated Armor, Crushing→Stun,
|
||||||
|
// Slashing→Bleeding Wound; Estoc=2H Penetrated Armor is the 2H physical build's core)
|
||||||
if (name.includes('estoc')) s *= 1.25;
|
if (name.includes('estoc')) s *= 1.25;
|
||||||
else if (name.includes('longsword')) s *= 1.10;
|
else if (name.includes('rapier')) s *= 1.20; // 1H Penetrated Armor
|
||||||
else if (name.includes('great mace')) s *= 0.90;
|
else if (name.includes('longsword') || name.includes('katana') || name.includes('shortsword') || name.includes('axe') || name.includes('wakizashi')) s *= 1.10; // Bleeding Wound
|
||||||
else if (name.includes('club')) s *= 0.85;
|
else if (name.includes('great mace') || name.includes('club') || name.includes('mace')) s *= 1.15; // Stun
|
||||||
else if (name.includes('axe')) s *= 0.90;
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name HV Unified
|
// @name HV Unified
|
||||||
// @namespace hvunified
|
// @namespace hvunified
|
||||||
// @version 0.15.3
|
// @version 0.15.4
|
||||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||||
// @author GaboGG + Hermes
|
// @author GaboGG + Hermes
|
||||||
// @match *://*.hentaiverse.org/*
|
// @match *://*.hentaiverse.org/*
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
// CONFIG — default settings
|
// CONFIG — default settings
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
const VERSION = '0.15.3';
|
const VERSION = '0.15.4';
|
||||||
|
|
||||||
const CFG = {
|
const CFG = {
|
||||||
// — Battle automation
|
// — Battle automation
|
||||||
|
|
@ -3528,7 +3528,16 @@ function parseEquipHTML(htmlStr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weapon damage line: "+708 Piercing Damage"
|
// Elemental Strike line (wiki: "X Strike (Y%)" — e.g. "Void Strike (50%)")
|
||||||
|
// Additional ~50%-of-physical-damage hit; max 2 strikes + Void Strike.
|
||||||
|
const strikeM = text.match(/^([A-Za-z]+)\s+Strike\s*\(\s*(\d+)%\s*\)$/);
|
||||||
|
if (strikeM) {
|
||||||
|
stats['Strike ' + strikeM[1]] = parseInt(strikeM[2]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Weapon damage line: "+523 Void Damage" / "+708 Piercing Damage"
|
||||||
|
// Base type can be Slashing/Crushing/Piercing, or Void for Ethereal.
|
||||||
const dmgM = text.match(/^\+([\d,]+)\s*([A-Za-z]+)\s*Damage$/);
|
const dmgM = text.match(/^\+([\d,]+)\s*([A-Za-z]+)\s*Damage$/);
|
||||||
if (dmgM) {
|
if (dmgM) {
|
||||||
stats['Weapon Damage'] = parseInt(dmgM[1].replace(/,/g, ''));
|
stats['Weapon Damage'] = parseInt(dmgM[1].replace(/,/g, ''));
|
||||||
|
|
@ -3864,11 +3873,17 @@ function gearScoreWeapon(item) {
|
||||||
s += _num(st['Block']) * 0.5;
|
s += _num(st['Block']) * 0.5;
|
||||||
s += _num(st['Agility']) * 0.5;
|
s += _num(st['Agility']) * 0.5;
|
||||||
s -= _num(st['burden']) * 0.5;
|
s -= _num(st['burden']) * 0.5;
|
||||||
// Base weapon damage (e.g. "+708 Piercing Damage") — scales with quality
|
// Base weapon damage (e.g. "+708 Piercing Damage", "+523 Void Damage") — scales with quality
|
||||||
s += _num(st['Weapon Damage']) * 0.30;
|
const wd = _num(st['Weapon Damage']);
|
||||||
// Elemental damage lines (e.g. "+25 Fire Damage", "+30 Elec Strike")
|
s += wd * 0.30;
|
||||||
['Fire', 'Cold', 'Elec', 'Wind', 'Holy', 'Dark', 'Ethereal', 'Elemental'].forEach(el => {
|
// Elemental Strikes (wiki: "X Strike (Y%)" — separate hit for ~50% of physical damage)
|
||||||
s += _num(st['Elemental ' + el]) * 0.25;
|
// Expected damage = chance% × 0.5 × weapon damage. Weight same as base damage (0.30).
|
||||||
|
['Fire', 'Cold', 'Elec', 'Wind', 'Holy', 'Dark', 'Void', 'Ethereal'].forEach(el => {
|
||||||
|
const chance = _num(st['Strike ' + el]);
|
||||||
|
if (chance > 0) {
|
||||||
|
const expected = (chance / 100) * 0.5 * wd;
|
||||||
|
s += expected > 0 ? expected * 0.30 : chance * 0.15;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// Proc lines: elemental/status procs add value (e.g. "Proc Penetrated Armor: 21.7%")
|
// Proc lines: elemental/status procs add value (e.g. "Proc Penetrated Armor: 21.7%")
|
||||||
let procBonus = 0;
|
let procBonus = 0;
|
||||||
|
|
@ -3885,12 +3900,12 @@ function gearScoreWeapon(item) {
|
||||||
s += procBonus;
|
s += procBonus;
|
||||||
// Quality multiplier (q6=Magnificent, q5=Exquisite, q4=Superior)
|
// Quality multiplier (q6=Magnificent, q5=Exquisite, q4=Superior)
|
||||||
s *= 0.8 + (quality * 0.12);
|
s *= 0.8 + (quality * 0.12);
|
||||||
// Weapon type bonus
|
// Weapon type bonus (wiki procs: Piercing→Penetrated Armor, Crushing→Stun,
|
||||||
|
// Slashing→Bleeding Wound; Estoc=2H Penetrated Armor is the 2H physical build's core)
|
||||||
if (name.includes('estoc')) s *= 1.25;
|
if (name.includes('estoc')) s *= 1.25;
|
||||||
else if (name.includes('longsword')) s *= 1.10;
|
else if (name.includes('rapier')) s *= 1.20; // 1H Penetrated Armor
|
||||||
else if (name.includes('great mace')) s *= 0.90;
|
else if (name.includes('longsword') || name.includes('katana') || name.includes('shortsword') || name.includes('axe') || name.includes('wakizashi')) s *= 1.10; // Bleeding Wound
|
||||||
else if (name.includes('club')) s *= 0.85;
|
else if (name.includes('great mace') || name.includes('club') || name.includes('mace')) s *= 1.15; // Stun
|
||||||
else if (name.includes('axe')) s *= 0.90;
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// CONFIG — default settings
|
// CONFIG — default settings
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
const VERSION = '0.15.3';
|
const VERSION = '0.15.4';
|
||||||
|
|
||||||
const CFG = {
|
const CFG = {
|
||||||
// — Battle automation
|
// — Battle automation
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,17 @@ function gearScoreWeapon(item) {
|
||||||
s += _num(st['Block']) * 0.5;
|
s += _num(st['Block']) * 0.5;
|
||||||
s += _num(st['Agility']) * 0.5;
|
s += _num(st['Agility']) * 0.5;
|
||||||
s -= _num(st['burden']) * 0.5;
|
s -= _num(st['burden']) * 0.5;
|
||||||
// Base weapon damage (e.g. "+708 Piercing Damage") — scales with quality
|
// Base weapon damage (e.g. "+708 Piercing Damage", "+523 Void Damage") — scales with quality
|
||||||
s += _num(st['Weapon Damage']) * 0.30;
|
const wd = _num(st['Weapon Damage']);
|
||||||
// Elemental damage lines (e.g. "+25 Fire Damage", "+30 Elec Strike")
|
s += wd * 0.30;
|
||||||
['Fire', 'Cold', 'Elec', 'Wind', 'Holy', 'Dark', 'Ethereal', 'Elemental'].forEach(el => {
|
// Elemental Strikes (wiki: "X Strike (Y%)" — separate hit for ~50% of physical damage)
|
||||||
s += _num(st['Elemental ' + el]) * 0.25;
|
// Expected damage = chance% × 0.5 × weapon damage. Weight same as base damage (0.30).
|
||||||
|
['Fire', 'Cold', 'Elec', 'Wind', 'Holy', 'Dark', 'Void', 'Ethereal'].forEach(el => {
|
||||||
|
const chance = _num(st['Strike ' + el]);
|
||||||
|
if (chance > 0) {
|
||||||
|
const expected = (chance / 100) * 0.5 * wd;
|
||||||
|
s += expected > 0 ? expected * 0.30 : chance * 0.15;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// Proc lines: elemental/status procs add value (e.g. "Proc Penetrated Armor: 21.7%")
|
// Proc lines: elemental/status procs add value (e.g. "Proc Penetrated Armor: 21.7%")
|
||||||
let procBonus = 0;
|
let procBonus = 0;
|
||||||
|
|
@ -66,12 +72,12 @@ function gearScoreWeapon(item) {
|
||||||
s += procBonus;
|
s += procBonus;
|
||||||
// Quality multiplier (q6=Magnificent, q5=Exquisite, q4=Superior)
|
// Quality multiplier (q6=Magnificent, q5=Exquisite, q4=Superior)
|
||||||
s *= 0.8 + (quality * 0.12);
|
s *= 0.8 + (quality * 0.12);
|
||||||
// Weapon type bonus
|
// Weapon type bonus (wiki procs: Piercing→Penetrated Armor, Crushing→Stun,
|
||||||
|
// Slashing→Bleeding Wound; Estoc=2H Penetrated Armor is the 2H physical build's core)
|
||||||
if (name.includes('estoc')) s *= 1.25;
|
if (name.includes('estoc')) s *= 1.25;
|
||||||
else if (name.includes('longsword')) s *= 1.10;
|
else if (name.includes('rapier')) s *= 1.20; // 1H Penetrated Armor
|
||||||
else if (name.includes('great mace')) s *= 0.90;
|
else if (name.includes('longsword') || name.includes('katana') || name.includes('shortsword') || name.includes('axe') || name.includes('wakizashi')) s *= 1.10; // Bleeding Wound
|
||||||
else if (name.includes('club')) s *= 0.85;
|
else if (name.includes('great mace') || name.includes('club') || name.includes('mace')) s *= 1.15; // Stun
|
||||||
else if (name.includes('axe')) s *= 0.90;
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,16 @@ function parseEquipHTML(htmlStr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weapon damage line: "+708 Piercing Damage"
|
// Elemental Strike line (wiki: "X Strike (Y%)" — e.g. "Void Strike (50%)")
|
||||||
|
// Additional ~50%-of-physical-damage hit; max 2 strikes + Void Strike.
|
||||||
|
const strikeM = text.match(/^([A-Za-z]+)\s+Strike\s*\(\s*(\d+)%\s*\)$/);
|
||||||
|
if (strikeM) {
|
||||||
|
stats['Strike ' + strikeM[1]] = parseInt(strikeM[2]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Weapon damage line: "+523 Void Damage" / "+708 Piercing Damage"
|
||||||
|
// Base type can be Slashing/Crushing/Piercing, or Void for Ethereal.
|
||||||
const dmgM = text.match(/^\+([\d,]+)\s*([A-Za-z]+)\s*Damage$/);
|
const dmgM = text.match(/^\+([\d,]+)\s*([A-Za-z]+)\s*Damage$/);
|
||||||
if (dmgM) {
|
if (dmgM) {
|
||||||
stats['Weapon Damage'] = parseInt(dmgM[1].replace(/,/g, ''));
|
stats['Weapon Damage'] = parseInt(dmgM[1].replace(/,/g, ''));
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name HV Unified
|
// @name HV Unified
|
||||||
// @namespace hvunified
|
// @namespace hvunified
|
||||||
// @version 0.15.3
|
// @version 0.15.4
|
||||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||||
// @author GaboGG + Hermes
|
// @author GaboGG + Hermes
|
||||||
// @match *://*.hentaiverse.org/*
|
// @match *://*.hentaiverse.org/*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue