[Bug]: Damage above 1000 is split on comma

Fixes #696
This commit is contained in:
kvan7
2025-09-16 17:23:46 -05:00
parent 3eb7ef60a3
commit e094751650
3 changed files with 231 additions and 5 deletions

View File

@@ -3,6 +3,8 @@ import { __testExports } from "@/parser/Parser";
import { beforeEach, describe, expect, test } from "vitest"; import { beforeEach, describe, expect, test } from "vitest";
import { setupTests } from "@specs/vitest.setup"; import { setupTests } from "@specs/vitest.setup";
import { import {
ArmourHighValueRareItem,
HighDamageRareItem,
MagicItem, MagicItem,
NormalItem, NormalItem,
RareItem, RareItem,
@@ -10,6 +12,7 @@ import {
UniqueItem, UniqueItem,
} from "./items"; } from "./items";
import { loadForLang } from "@/assets/data"; import { loadForLang } from "@/assets/data";
import { ParsedItem } from "@/parser";
describe("itemTextToSections", () => { describe("itemTextToSections", () => {
beforeEach(async () => { beforeEach(async () => {
@@ -39,4 +42,100 @@ describe("itemTextToSections", () => {
const sections = __testExports.itemTextToSections(RareWithImplicit.rawText); const sections = __testExports.itemTextToSections(RareWithImplicit.rawText);
expect(sections.length).toBe(RareWithImplicit.sectionCount); expect(sections.length).toBe(RareWithImplicit.sectionCount);
}); });
test("high damage rare item", () => {
const sections = __testExports.itemTextToSections(
HighDamageRareItem.rawText,
);
expect(sections.length).toBe(HighDamageRareItem.sectionCount);
});
});
describe("parseWeapon", () => {
beforeEach(async () => {
setupTests();
await loadForLang("en");
});
test("Magic Weapon", () => {
const sections = __testExports.itemTextToSections(MagicItem.rawText);
const parsedItem = {} as ParsedItem;
const res = __testExports.parseWeapon(sections[1], parsedItem);
expect(res).toBe("SECTION_PARSED");
expect(parsedItem.weaponPHYSICAL).toBe(MagicItem.weaponPHYSICAL);
expect(parsedItem.weaponELEMENTAL).toBe(MagicItem.weaponELEMENTAL);
expect(parsedItem.weaponAS).toBe(MagicItem.weaponAS);
expect(parsedItem.weaponCRIT).toBe(MagicItem.weaponCRIT);
expect(parsedItem.weaponReload).toBe(MagicItem.weaponReload);
});
test("Rare Weapon", () => {
const sections = __testExports.itemTextToSections(RareItem.rawText);
const parsedItem = {} as ParsedItem;
const res = __testExports.parseWeapon(sections[1], parsedItem);
expect(res).toBe("SECTION_PARSED");
expect(parsedItem.weaponPHYSICAL).toBe(RareItem.weaponPHYSICAL);
expect(parsedItem.weaponELEMENTAL).toBe(RareItem.weaponELEMENTAL);
expect(parsedItem.weaponAS).toBe(RareItem.weaponAS);
expect(parsedItem.weaponCRIT).toBe(RareItem.weaponCRIT);
expect(parsedItem.weaponReload).toBe(RareItem.weaponReload);
});
test("High Damage Rare Weapon", () => {
const sections = __testExports.itemTextToSections(
HighDamageRareItem.rawText,
);
const parsedItem = {} as ParsedItem;
const res = __testExports.parseWeapon(sections[1], parsedItem);
expect(res).toBe("SECTION_PARSED");
expect(parsedItem.weaponPHYSICAL).toBe(HighDamageRareItem.weaponPHYSICAL);
expect(parsedItem.weaponELEMENTAL).toBe(HighDamageRareItem.weaponELEMENTAL);
expect(parsedItem.weaponAS).toBe(HighDamageRareItem.weaponAS);
expect(parsedItem.weaponCRIT).toBe(HighDamageRareItem.weaponCRIT);
expect(parsedItem.weaponReload).toBe(HighDamageRareItem.weaponReload);
});
});
describe("parseArmour", () => {
beforeEach(async () => {
setupTests();
await loadForLang("en");
});
test("Normal Armour", () => {
const sections = __testExports.itemTextToSections(NormalItem.rawText);
const parsedItem = {} as ParsedItem;
const res = __testExports.parseArmour(sections[1], parsedItem);
expect(res).toBe("SECTION_PARSED");
expect(parsedItem.armourAR).toBe(NormalItem.armourAR);
expect(parsedItem.armourEV).toBe(NormalItem.armourEV);
expect(parsedItem.armourES).toBe(NormalItem.armourES);
});
test("Unique Armour", () => {
const sections = __testExports.itemTextToSections(UniqueItem.rawText);
const parsedItem = {} as ParsedItem;
const res = __testExports.parseArmour(sections[1], parsedItem);
expect(res).toBe("SECTION_PARSED");
expect(parsedItem.armourAR).toBe(UniqueItem.armourAR);
expect(parsedItem.armourEV).toBe(UniqueItem.armourEV);
expect(parsedItem.armourES).toBe(UniqueItem.armourES);
});
test("High Armour Rare", () => {
const sections = __testExports.itemTextToSections(
ArmourHighValueRareItem.rawText,
);
const parsedItem = {} as ParsedItem;
const res = __testExports.parseArmour(sections[1], parsedItem);
expect(res).toBe("SECTION_PARSED");
expect(parsedItem.armourAR).toBe(ArmourHighValueRareItem.armourAR);
expect(parsedItem.armourEV).toBe(ArmourHighValueRareItem.armourEV);
expect(parsedItem.armourES).toBe(ArmourHighValueRareItem.armourES);
});
}); });

View File

@@ -58,6 +58,7 @@ class TestItem implements ParsedItem {
} }
| undefined; | undefined;
note?: string;
category?: ItemCategory | undefined; category?: ItemCategory | undefined;
info: BaseType = { info: BaseType = {
name: "test", name: "test",
@@ -145,6 +146,7 @@ MagicItem.category = ItemCategory.TwoHandedMace;
MagicItem.rarity = ItemRarity.Magic; MagicItem.rarity = ItemRarity.Magic;
MagicItem.weaponPHYSICAL = 53.5; MagicItem.weaponPHYSICAL = 53.5;
MagicItem.weaponLIGHTNING = 25.5; MagicItem.weaponLIGHTNING = 25.5;
MagicItem.weaponELEMENTAL = MagicItem.weaponLIGHTNING;
MagicItem.weaponCRIT = 5; MagicItem.weaponCRIT = 5;
MagicItem.weaponAS = 1.2; MagicItem.weaponAS = 1.2;
MagicItem.itemLevel = 32; MagicItem.itemLevel = 32;
@@ -187,6 +189,8 @@ RareItem.weaponCOLD = 11;
RareItem.weaponLIGHTNING = 43.5; RareItem.weaponLIGHTNING = 43.5;
RareItem.weaponELEMENTAL = RareItem.weaponELEMENTAL =
RareItem.weaponFIRE + RareItem.weaponCOLD + RareItem.weaponLIGHTNING; RareItem.weaponFIRE + RareItem.weaponCOLD + RareItem.weaponLIGHTNING;
RareItem.weaponAS = 1.2;
RareItem.weaponCRIT = 5;
RareItem.itemLevel = 80; RareItem.itemLevel = 80;
RareItem.sectionCount = 5; RareItem.sectionCount = 5;
@@ -340,3 +344,113 @@ UncutSupportGem.info = {
UncutSupportGem.sectionCount = 5; UncutSupportGem.sectionCount = 5;
// #endregion // #endregion
// #region HighDamageRareItem
export const HighDamageRareItem = new TestItem(`Item Class: Crossbows
Rarity: Rare
Dragon Core
Siege Crossbow
--------
Quality: +29% (augmented)
Physical Damage: 414-1,043 (augmented)
Critical Hit Chance: 5.00%
Attacks per Second: 2.07 (augmented)
Reload Time: 0.60 (augmented)
--------
Requires: Level 79, 89 (unmet) Str, 89 Dex
--------
Sockets: S S
--------
Item Level: 82
--------
36% increased Physical Damage (rune)
--------
{ Implicit Modifier }
Grenade Skills Fire an additional Projectile (implicit)
--------
{ Prefix Modifier "Merciless" (Tier: 1) — Damage, Physical, Attack }
173(170-179)% increased Physical Damage
{ Prefix Modifier "Dictator's" (Tier: 1) — Damage, Physical, Attack }
78(75-79)% increased Physical Damage
+175(175-200) to Accuracy Rating
{ Prefix Modifier "Flaring" (Tier: 1) — Damage, Physical, Attack }
Adds 54(37-55) to 94(63-94) Physical Damage (desecrated)
{ Suffix Modifier "of Infamy" — Attack, Speed }
25(23-25)% increased Attack Speed (fractured)
{ Suffix Modifier "of the Sniper" (Tier: 1) }
+7 to Level of all Projectile Skills
{ Suffix Modifier "of Bursting" (Tier: 1) — Attack }
Loads 2 additional bolts
--------
Fractured Item
`);
HighDamageRareItem.category = ItemCategory.Crossbow;
HighDamageRareItem.rarity = ItemRarity.Rare;
HighDamageRareItem.weaponPHYSICAL = 728.5;
HighDamageRareItem.weaponAS = 2.07;
HighDamageRareItem.weaponCRIT = 5;
HighDamageRareItem.weaponReload = 0.6;
HighDamageRareItem.itemLevel = 82;
HighDamageRareItem.sectionCount = 9;
HighDamageRareItem.prefixCount = 3;
HighDamageRareItem.suffixCount = 3;
HighDamageRareItem.implicitCount = 1;
HighDamageRareItem.runeSockets = {
empty: 0,
current: 2,
normal: 2,
};
// #endregion
// #region ArmourHighValueRareItem
export const ArmourHighValueRareItem = new TestItem(`Item Class: Body Armours
Rarity: Rare
Hate Pelt
Soldier Cuirass
--------
Quality: +20% (augmented)
Armour: 3075 (augmented)
--------
Requires: Level 65, 121 (unmet) Str
--------
Sockets: S S S
--------
Item Level: 80
--------
54% increased Armour, Evasion and Energy Shield (rune)
--------
{ Prefix Modifier "Impenetrable" (Tier: 1) — Defences }
103(101-110)% increased Armour
{ Prefix Modifier "Hardened" (Tier: 1) — Defences }
+70(70-86) to Armour
41(39-42)% increased Armour
{ Prefix Modifier "Unmoving" (Tier: 2) — Defences }
+256(226-256) to Armour (desecrated)
{ Suffix Modifier "of the Titan" (Tier: 1) — Attribute }
+32(31-33) to Strength
{ Suffix Modifier "of Allaying" (Tier: 3) — Physical, Ailment }
48(50-46)% reduced Duration of Bleeding on You
{ Suffix Modifier "of the Essence" (Tier: 1) }
Hits against you have 44(40-50)% reduced Critical Damage Bonus
--------
Note: ~b/o 10 divine
`);
ArmourHighValueRareItem.category = ItemCategory.BodyArmour;
ArmourHighValueRareItem.rarity = ItemRarity.Rare;
ArmourHighValueRareItem.armourAR = 3075;
ArmourHighValueRareItem.itemLevel = 80;
ArmourHighValueRareItem.sectionCount = 8;
ArmourHighValueRareItem.prefixCount = 3;
ArmourHighValueRareItem.suffixCount = 3;
ArmourHighValueRareItem.implicitCount = 1;
ArmourHighValueRareItem.runeSockets = {
empty: 0,
current: 3,
normal: 2,
};
ArmourHighValueRareItem.note = "~b/o 10 divine";
// #endregion

View File

@@ -729,11 +729,13 @@ function parseWeapon(section: string[], item: ParsedItem) {
for (const line of section) { for (const line of section) {
if (line.startsWith(_$.CRIT_CHANCE)) { if (line.startsWith(_$.CRIT_CHANCE)) {
// No regex since it can have decimals
item.weaponCRIT = parseFloat(line.slice(_$.CRIT_CHANCE.length)); item.weaponCRIT = parseFloat(line.slice(_$.CRIT_CHANCE.length));
isParsed = "SECTION_PARSED"; isParsed = "SECTION_PARSED";
continue; continue;
} }
if (line.startsWith(_$.ATTACK_SPEED)) { if (line.startsWith(_$.ATTACK_SPEED)) {
// No regex since it can have decimals
item.weaponAS = parseFloat(line.slice(_$.ATTACK_SPEED.length)); item.weaponAS = parseFloat(line.slice(_$.ATTACK_SPEED.length));
isParsed = "SECTION_PARSED"; isParsed = "SECTION_PARSED";
continue; continue;
@@ -743,7 +745,7 @@ function parseWeapon(section: string[], item: ParsedItem) {
line line
.slice(_$.PHYSICAL_DAMAGE.length) .slice(_$.PHYSICAL_DAMAGE.length)
.split(_$.HYPHEN) .split(_$.HYPHEN)
.map((str) => parseInt(str, 10)), .map((str) => parseInt(str.replace(/[^\d]/g, ""), 10)),
); );
isParsed = "SECTION_PARSED"; isParsed = "SECTION_PARSED";
continue; continue;
@@ -754,7 +756,9 @@ function parseWeapon(section: string[], item: ParsedItem) {
.split(", ") .split(", ")
.map((element) => .map((element) =>
getRollOrMinmaxAvg( getRollOrMinmaxAvg(
element.split(_$.HYPHEN).map((str) => parseInt(str, 10)), element
.split(_$.HYPHEN)
.map((str) => parseInt(str.replace(/[^\d]/g, ""), 10)),
), ),
) )
.reduce((sum, x) => sum + x, 0); .reduce((sum, x) => sum + x, 0);
@@ -768,7 +772,9 @@ function parseWeapon(section: string[], item: ParsedItem) {
.split(", ") .split(", ")
.map((element) => .map((element) =>
getRollOrMinmaxAvg( getRollOrMinmaxAvg(
element.split(_$.HYPHEN).map((str) => parseInt(str, 10)), element
.split(_$.HYPHEN)
.map((str) => parseInt(str.replace(/[^\d]/g, ""), 10)),
), ),
) )
.reduce((sum, x) => sum + x, 0); .reduce((sum, x) => sum + x, 0);
@@ -786,7 +792,9 @@ function parseWeapon(section: string[], item: ParsedItem) {
.split(", ") .split(", ")
.map((element) => .map((element) =>
getRollOrMinmaxAvg( getRollOrMinmaxAvg(
element.split(_$.HYPHEN).map((str) => parseInt(str, 10)), element
.split(_$.HYPHEN)
.map((str) => parseInt(str.replace(/[^\d]/g, ""), 10)),
), ),
) )
.reduce((sum, x) => sum + x, 0); .reduce((sum, x) => sum + x, 0);
@@ -804,7 +812,9 @@ function parseWeapon(section: string[], item: ParsedItem) {
.split(", ") .split(", ")
.map((element) => .map((element) =>
getRollOrMinmaxAvg( getRollOrMinmaxAvg(
element.split(_$.HYPHEN).map((str) => parseInt(str, 10)), element
.split(_$.HYPHEN)
.map((str) => parseInt(str.replace(/[^\d]/g, ""), 10)),
), ),
) )
.reduce((sum, x) => sum + x, 0); .reduce((sum, x) => sum + x, 0);
@@ -817,6 +827,7 @@ function parseWeapon(section: string[], item: ParsedItem) {
continue; continue;
} }
if (line.startsWith(_$.RELOAD_SPEED)) { if (line.startsWith(_$.RELOAD_SPEED)) {
// No regex since it can have decimals
item.weaponReload = parseFloat(line.slice(_$.RELOAD_SPEED.length)); item.weaponReload = parseFloat(line.slice(_$.RELOAD_SPEED.length));
isParsed = "SECTION_PARSED"; isParsed = "SECTION_PARSED";
continue; continue;
@@ -1688,4 +1699,6 @@ export const __testExports = {
itemTextToSections, itemTextToSections,
parseNamePlate, parseNamePlate,
isUncutSkillGem, isUncutSkillGem,
parseWeapon,
parseArmour,
}; };