Skip to content

Commit cec836d

Browse files
authored
(S12) Bloodied items should now be read correctly (#640)
1 parent 6450c0d commit cec836d

File tree

4 files changed

+184
-26
lines changed

4 files changed

+184
-26
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ feature request or issue reports join the [discord](https://discord.gg/YyzaPhAN6
2828
- In Battle.net, click the gear icon next to the Play button and select "Open in Explorer"
2929
- In Steam, right click the game, select Manage > Browse local files
3030
- **New for Season 12** The saapi64.dll must be locally signed for D4 to pick it up. We have written a script to do this for you. It is a one-time process per computer.
31+
- If you are on Windows 10, you need to install Windows SDK Signing Tools from this link: https://go.microsoft.com/fwlink/?linkid=2311805
3132
- Navigate to your d4lf directory
3233
- Right click and choose "Open in Terminal"
3334
- Type the following: `.\sign_dll.ps1`

src/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
TP = concurrent.futures.ThreadPoolExecutor()
44

5-
__version__ = "8.2.0"
5+
__version__ = "8.2.1"

src/item/descr/read_descr_tts.py

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def _get_affix_counts(tts_section: list[str], item: Item, start: int) -> tuple[i
7676
# This will also grab up slotted gems but we really don't have much choice
7777
if item.rarity == ItemRarity.Rare and any(
7878
tts_section[start + inherent_num + affixes_num - 1].lower().startswith(x)
79-
for x in ["empty socket", "requires level", "properties lost when equipped"]
79+
for x in ["empty socket", "requires level", "properties lost when equipped", "rampage:", "feast:", "hunger:"]
8080
):
8181
affixes_num = 3
8282
elif item.rarity == ItemRarity.Legendary and tts_section[start + inherent_num + affixes_num - 1].lower().startswith(
@@ -91,7 +91,8 @@ def _get_affix_counts(tts_section: list[str], item: Item, start: int) -> tuple[i
9191
def _add_affixes_from_tts(tts_section: list[str], item: Item) -> Item:
9292
starting_index = _get_affix_starting_location_from_tts_section(tts_section, item)
9393
inherent_num, affixes_num = _get_affix_counts(tts_section, item, starting_index)
94-
affixes = _get_affixes_from_tts_section(tts_section, item, starting_index, inherent_num + affixes_num)
94+
affixes = _get_affixes_from_tts_section(tts_section, starting_index, inherent_num + affixes_num)
95+
aspect_text = _get_aspect_from_tts_section(tts_section, item, starting_index, len(affixes))
9596
for i, affix_text in enumerate(affixes):
9697
if i < inherent_num:
9798
affix = _get_affix_from_text(affix_text)
@@ -100,12 +101,14 @@ def _add_affixes_from_tts(tts_section: list[str], item: Item) -> Item:
100101
elif i < inherent_num + affixes_num:
101102
affix = _get_affix_from_text(affix_text)
102103
item.affixes.append(affix)
103-
elif item.rarity == ItemRarity.Mythic:
104-
item.aspect = Aspect(name=item.name, text=affix_text, value=find_number(affix_text))
104+
105+
if aspect_text:
106+
if item.rarity == ItemRarity.Mythic:
107+
item.aspect = Aspect(name=item.name, text=aspect_text, value=find_number(aspect_text))
105108
elif item.rarity == ItemRarity.Unique:
106-
item.aspect = _get_aspect_from_text(affix_text, item.name)
109+
item.aspect = _get_aspect_from_text(aspect_text, item.name)
107110
else:
108-
item.aspect = _get_aspect_from_name(affix_text, item.name)
111+
item.aspect = _get_aspect_from_name(aspect_text, item.name)
109112
return item
110113

111114

@@ -118,7 +121,8 @@ def _add_affixes_from_tts_mixed(
118121
) -> Item:
119122
starting_index = _get_affix_starting_location_from_tts_section(tts_section, item)
120123
inherent_num, affixes_num = _get_affix_counts(tts_section, item, starting_index)
121-
affixes = _get_affixes_from_tts_section(tts_section, item, starting_index, inherent_num + affixes_num)
124+
affixes = _get_affixes_from_tts_section(tts_section, starting_index, inherent_num + affixes_num)
125+
aspect_text = _get_aspect_from_tts_section(tts_section, item, starting_index, len(affixes))
122126

123127
# With advanced item compare on we'll actually find more bullets than we need, so we don't rely on them for number of affixes
124128
if len(affixes) - 1 > len(affix_bullets):
@@ -140,22 +144,23 @@ def _add_affixes_from_tts_mixed(
140144
else:
141145
affix.type = AffixType.normal
142146
item.affixes.append(affix)
147+
148+
if aspect_text:
149+
if item.rarity == ItemRarity.Mythic:
150+
item.aspect = Aspect(name=item.name, text=aspect_text, value=find_number(aspect_text))
151+
elif item.rarity == ItemRarity.Unique:
152+
item.aspect = _get_aspect_from_text(aspect_text, item.name)
143153
else:
144-
if item.rarity == ItemRarity.Mythic:
145-
item.aspect = Aspect(name=item.name, text=affix_text, value=find_number(affix_text))
146-
elif item.rarity == ItemRarity.Unique:
147-
item.aspect = _get_aspect_from_text(affix_text, item.name)
154+
item.aspect = _get_aspect_from_name(aspect_text, item.name)
155+
if item.aspect:
156+
if not aspect_bullet:
157+
LOGGER.warning(
158+
"No bullet was found for the aspect. If the aspect's first line is partially or fully off "
159+
"the screen, you can ignore this warning. Otherwise, please report a bug with a screenshot "
160+
"of the item."
161+
)
148162
else:
149-
item.aspect = _get_aspect_from_name(affix_text, item.name)
150-
if item.aspect:
151-
if not aspect_bullet:
152-
LOGGER.warning(
153-
"No bullet was found for the aspect. If the aspect's first line is partially or fully off "
154-
"the screen, you can ignore this warning. Otherwise, please report a bug with a screenshot "
155-
"of the item."
156-
)
157-
else:
158-
item.aspect.loc = aspect_bullet.center
163+
item.aspect.loc = aspect_bullet.center
159164
return item
160165

161166

@@ -260,7 +265,7 @@ def _create_base_item_from_tts(tts_item: list[str]) -> Item | None:
260265
if any("sanctified" in tts_item[i].lower() for i in range(3, min(7, len(tts_item)))):
261266
item.seasonal_attribute = SeasonalAttribute.sanctified
262267

263-
search_string = tts_item[1].lower().replace("ancestral", "").replace("chaos", "").strip()
268+
search_string = tts_item[1].lower().replace("ancestral", "").replace("bloodied", "").strip()
264269
search_string = _REPLACE_COMPARE_RE.sub("", search_string).strip()
265270
search_string_split = search_string.split(" ")
266271
item.rarity = _get_item_rarity(search_string_split[0])
@@ -311,12 +316,19 @@ def _get_index_of_armor_dps_or_all_resist(tts_section: list[str], indicator: str
311316
return 0
312317

313318

314-
def _get_affixes_from_tts_section(tts_section: list[str], item: Item, start: int, length: int):
319+
def _get_affixes_from_tts_section(tts_section: list[str], start: int, length: int):
320+
return tts_section[start : start + length]
321+
322+
323+
def _get_aspect_from_tts_section(tts_section: list[str], item: Item, start: int, num_affixes: int):
315324
# Grab the aspect as well in this case
316325
if item.rarity in [ItemRarity.Mythic, ItemRarity.Unique, ItemRarity.Legendary]:
317-
length += 1
326+
aspect_index = start + num_affixes
327+
if item.seasonal_attribute == SeasonalAttribute.bloodied:
328+
aspect_index = aspect_index + 1
329+
return tts_section[aspect_index]
318330

319-
return tts_section[start : start + length]
331+
return None
320332

321333

322334
def _get_affix_from_text(text: str) -> Affix:
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import pytest
2+
3+
import src.tts
4+
from src.item.data.affix import Affix, AffixType
5+
from src.item.data.aspect import Aspect
6+
from src.item.data.item_type import ItemType
7+
from src.item.data.rarity import ItemRarity
8+
from src.item.data.seasonal_attribute import SeasonalAttribute
9+
from src.item.descr.read_descr_tts import read_descr
10+
from src.item.models import Item
11+
12+
items = [
13+
(
14+
# The next 3 tests are bloodied items
15+
[
16+
"INIMICAL SEAL OF PILGRIMS PROGRESS",
17+
"Bloodied Legendary Amulet",
18+
"383 Item Power",
19+
"70 All Resist (-2.2% Toughness)",
20+
"+19 Strength +[18 - 20]",
21+
"+8 Maximum Life [8 - 10]",
22+
"+1 Faith On Kill +[1]",
23+
"+10.1% Movement Speed [6.6 - 11.6]%",
24+
"Hunger: 10% increased chance for Rampage Items during Kill Streaks [10]%",
25+
"Your Disciple Skills with Cooldowns generate up to 30 Faith based on how far your travel with them.",
26+
"Requires Level 34. Lord of Hatred Item",
27+
"Unlocks new Aspect in the Codex of Power on salvage",
28+
"Sell Value: 9,284 Gold",
29+
"Tempers: 3/3",
30+
"Right mouse button",
31+
],
32+
Item(
33+
affixes=[
34+
Affix(
35+
max_value=20.0,
36+
min_value=18.0,
37+
name="strength",
38+
text="+19 Strength +[18 - 20]",
39+
type=AffixType.normal,
40+
value=19.0,
41+
),
42+
Affix(
43+
max_value=10.0,
44+
min_value=8.0,
45+
name="maximum_life",
46+
text="+8 Maximum Life [8 - 10]",
47+
type=AffixType.normal,
48+
value=8.0,
49+
),
50+
Affix(
51+
max_value=1.0,
52+
min_value=1.0,
53+
name="faith_on_kill",
54+
text="+1 Faith On Kill +[1]",
55+
type=AffixType.normal,
56+
value=1.0,
57+
),
58+
Affix(
59+
max_value=11.6,
60+
min_value=6.6,
61+
name="movement_speed",
62+
text="+10.1% Movement Speed [6.6 - 11.6]%",
63+
type=AffixType.normal,
64+
value=10.1,
65+
),
66+
],
67+
aspect=Aspect(
68+
name="of_pilgrims_progress",
69+
text="Your Disciple Skills with Cooldowns generate up to 30 Faith based on how far your travel with them.",
70+
),
71+
codex_upgrade=True,
72+
cosmetic_upgrade=False,
73+
inherent=[],
74+
is_in_shop=False,
75+
item_type=ItemType.Amulet,
76+
name="inimical_seal_of_pilgrims_progress",
77+
original_name="INIMICAL SEAL OF PILGRIMS PROGRESS",
78+
power=383,
79+
rarity=ItemRarity.Legendary,
80+
seasonal_attribute=SeasonalAttribute.bloodied,
81+
),
82+
),
83+
(
84+
[
85+
"LURKING SNARE",
86+
"Bloodied Rare Gloves",
87+
"393 Item Power",
88+
"295 Armor (+1.6% Toughness)",
89+
"+24 Strength +[24 - 26]",
90+
"+9 Maximum Life [8 - 10]",
91+
"2.5% Resource Cost Reduction [2.2 - 2.5]%",
92+
"Rampage: +8% Critical Strike Chance per Kill Streak Tier [8]%",
93+
"Requires Level 38",
94+
"Sell Value: 2,775 Gold",
95+
"Durability: 100/100. Tempers: 1/1",
96+
"Right mouse button",
97+
],
98+
Item(
99+
affixes=[
100+
Affix(
101+
max_value=26.0,
102+
min_value=24.0,
103+
name="strength",
104+
text="+24 Strength +[24 - 26]",
105+
type=AffixType.normal,
106+
value=24.0,
107+
),
108+
Affix(
109+
max_value=10.0,
110+
min_value=8.0,
111+
name="maximum_life",
112+
text="+9 Maximum Life [8 - 10]",
113+
type=AffixType.normal,
114+
value=9.0,
115+
),
116+
Affix(
117+
max_value=2.5,
118+
min_value=2.2,
119+
name="resource_cost_reduction",
120+
text="2.5% Resource Cost Reduction [2.2 - 2.5]%",
121+
type=AffixType.normal,
122+
value=2.5,
123+
),
124+
],
125+
aspect=None,
126+
codex_upgrade=False,
127+
cosmetic_upgrade=False,
128+
inherent=[],
129+
is_in_shop=False,
130+
item_type=ItemType.Gloves,
131+
name="lurking_snare",
132+
original_name="LURKING SNARE",
133+
power=393,
134+
rarity=ItemRarity.Rare,
135+
seasonal_attribute=SeasonalAttribute.bloodied,
136+
),
137+
),
138+
]
139+
140+
141+
@pytest.mark.parametrize(("input_item", "expected_item"), items)
142+
def test_items(input_item: list[str], expected_item: Item):
143+
src.tts.LAST_ITEM = input_item
144+
item = read_descr()
145+
assert item == expected_item

0 commit comments

Comments
 (0)