251 lines
10 KiB
Python
251 lines
10 KiB
Python
import unittest
|
|
from d2warehouse.parser import parse_item
|
|
from d2warehouse.item import Quality, lookup_affix, lookup_runeword
|
|
|
|
|
|
class ParseItemTest(unittest.TestCase):
|
|
def test_gem(self):
|
|
# chipped diamond
|
|
data = bytes.fromhex("1000a0000524740910")
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(item.code, "gcw")
|
|
self.assertEqual(item.pos_x, 9)
|
|
self.assertEqual(item.pos_y, 0)
|
|
self.assertTrue(item.is_simple)
|
|
|
|
def test_buckler(self):
|
|
# white buckler
|
|
data = bytes.fromhex("10008000050054a1083f57a9190c01041818fc07")
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(item.code, "buc")
|
|
self.assertEqual(item.pos_x, 0)
|
|
self.assertEqual(item.pos_y, 0)
|
|
self.assertEqual(item.quality, Quality.NORMAL)
|
|
self.assertFalse(item.is_simple)
|
|
self.assertEqual(item.lvl, 12)
|
|
|
|
def test_rune(self):
|
|
# tal rune
|
|
data = bytes.fromhex("1000a0000564f67cfb00")
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(item.code, "r07")
|
|
self.assertEqual(item.pos_x, 9)
|
|
self.assertEqual(item.pos_y, 9)
|
|
self.assertTrue(item.is_simple)
|
|
|
|
def test_rare_a(self):
|
|
# random rare armor
|
|
data = bytes.fromhex(
|
|
"10008000050014df17c64083c30b866d534c958c39d15b42c0c1e1c08815cd9c04f80dff01"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(item.code, "hla")
|
|
self.assertEqual(item.pos_x, 0)
|
|
self.assertEqual(item.pos_y, 0)
|
|
self.assertEqual(item.quality, Quality.RARE)
|
|
self.assertFalse(item.is_simple)
|
|
self.assertEqual(item.lvl, 5)
|
|
self.assertEqual(len(item.stats), 4)
|
|
self.assertEqual(item.defense, 23)
|
|
self.assertEqual(item.durability, 28)
|
|
self.assertEqual(item.max_durability, 28)
|
|
|
|
def test_tp_tome(self):
|
|
data = bytes.fromhex("100080000500d4a814daf7275a180240e03f")
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(item.code, "tbk")
|
|
self.assertEqual(item.quantity, 4)
|
|
|
|
def test_superior_sockets(self):
|
|
# superior armor with empty sockets
|
|
data = bytes.fromhex("10088000050014df175043b1b90cc38d80e3834070b004f41f")
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(item.quality, Quality.HIGH)
|
|
self.assertEqual(len(item.stats), 2)
|
|
self.assertEqual(item.sockets, 2)
|
|
self.assertEqual(len(item.socketed_items), 0)
|
|
|
|
def test_ed_max(self):
|
|
# test bugfix for https://gitlab.com/omicron-oss/d2warehouse/-/issues/1
|
|
data = bytes.fromhex(
|
|
"10008000050094e6095cd89f590b23557340c2629612233cf09010a14183094260109c6866232080cc7f"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(item.code, "spr")
|
|
self.assertEqual(str(item.stats[0]), "+13% Enhanced Damage")
|
|
self.assertEqual(str(item.stats[2]), "+2 to Maximum Damage")
|
|
|
|
def test_runeword_lore(self):
|
|
# Lore: Ort Sol
|
|
data = bytes.fromhex(
|
|
"1008800405c055c637f1073af4558697412981070881506049e87f005516fb134582ff1000a0003500e07cbb001000a0003504e07c9800"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertTrue(item.is_runeword)
|
|
self.assertEqual(item.sockets, 2)
|
|
self.assertEqual(item.socketed_items[0].code, "r09")
|
|
self.assertEqual(item.socketed_items[1].code, "r12")
|
|
rw = lookup_runeword(item.runeword_id)
|
|
self.assertEqual(rw["name"], "Lore")
|
|
self.assertEqual(str(item.stats[4]), "+1 to All Skills") # runeword stat
|
|
self.assertEqual(str(item.stats[2]), "+10 to Energy") # runeword stat
|
|
# TODO: sol rune stat -- should it be in representation?
|
|
# self.assertEqual(str(item.sockets[1].stats[0]), "Lightning Resist 30%")
|
|
|
|
def test_item_with_implicit(self):
|
|
# A 3 socket heraldic shield with 13 all res
|
|
data = bytes.fromhex(
|
|
"10088000054074be6dd0113247e788182002141273a25a8a6a2baab5a8f61f"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(item.implicit, 24) # Rainbow, 8-15 all res
|
|
self.assertEqual(str(item.stats[0]), "Fire Resist +13%")
|
|
self.assertEqual(str(item.stats[1]), "Lightning Resist +13%")
|
|
self.assertEqual(str(item.stats[2]), "Cold Resist +13%")
|
|
self.assertEqual(str(item.stats[3]), "Poison Resist +13%")
|
|
|
|
def test_stackable_weapon(self):
|
|
data = bytes.fromhex("10208000054814dddb852a79b4708640408096ff")
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
|
|
def test_token_of_absolution(self):
|
|
# this is one of the items that had stackable "0" instead of ""
|
|
data = bytes.fromhex("100080000524d4fc5f308dc1e10908fe03")
|
|
data, item = parse_item(data)
|
|
|
|
def test_stat_to_class_skills(self):
|
|
# Redeemer with +2 to Paladin skill levels
|
|
data = bytes.fromhex(
|
|
"1000800005c4d593081e37d107dfa330c868881031e29429cb6d415953466bf8eccd1c3aa13ce9fe03"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(str(item.stats[1]), "+2 to Paladin Skill Levels")
|
|
# Jalal with +2 to Druid skills levels
|
|
data = bytes.fromhex(
|
|
"1000800005c4753c2f5c4c4e3d638f8fd0068a08006802d020ac3a612e85b915e65a989b528d91dd41a1a8c02b0540ff01"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(str(item.stats[7]), "+2 to Druid Skill Levels")
|
|
|
|
def test_stat_min_max_damage(self):
|
|
# Magic javelin with 3 to minimum damage and 21 attack rating
|
|
# Mod is id 21 (mindmg)
|
|
# Note: Since this is a javelin, it also has the stat 159 (min throwing dmg)
|
|
data = bytes.fromhex(
|
|
"10008000050014dddb05074ae2c006f10e701010a065420515864fc37f"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(str(item.stats[1]), "+3 to Minimum Damage")
|
|
self.assertEqual(str(item.stats[2]), "+3 to Minimum Damage")
|
|
|
|
# Rare spear with 2 max dmg + some other stats
|
|
# Mod is id 24 (secondary_maxdmg)
|
|
data = bytes.fromhex(
|
|
"10008000050094e6095cd89f590b23557340c2629612233cf09010a14183094260109c6866232080cc7f"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(str(item.stats[2]), "+2 to Maximum Damage")
|
|
|
|
# Unique: Husoldal Evo
|
|
# Adds 20-32 damage mod + its other stats
|
|
# Mod is 2 stats: id 23 (secondary_mindmg) and id 24 (secondary_maxdmg)
|
|
data = bytes.fromhex(
|
|
"10008000051cd4611704229c67b1472db89111a158b109e95ca0308094c85d507502ff01"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(str(item.stats[2]), "+20 to Minimum Damage")
|
|
self.assertEqual(str(item.stats[3]), "+32 to Maximum Damage")
|
|
|
|
# Jewel with minimum & maximum damage (+ others)
|
|
# This jewel has all of the stats:
|
|
# Primary (21, 22)
|
|
# Secondary (23, 24)
|
|
# Throwing (159, 160)
|
|
data = bytes.fromhex(
|
|
"10008000050014dd004269ea621ed446f0e05be494e9d02b0e9ca8a058085c50300464045e7c524005fe03"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(str(item.stats[1]), "+10 to Minimum Damage")
|
|
self.assertEqual(str(item.stats[2]), "+1 to Maximum Damage")
|
|
self.assertEqual(str(item.stats[3]), "+10 to Minimum Damage")
|
|
self.assertEqual(str(item.stats[4]), "+1 to Maximum Damage")
|
|
self.assertEqual(str(item.stats[6]), "+10 to Minimum Damage")
|
|
self.assertEqual(str(item.stats[7]), "+1 to Maximum Damage")
|
|
|
|
def test_stat_indestructible(self):
|
|
# Shadow Killer, Unique claw with indestructible property
|
|
data = bytes.fromhex(
|
|
"1000c0000580d40b0aa72367d4d7c32920f588e0cc199d8c21a16881a9318485d07f"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(str(item.stats[4]), "Indestructible")
|
|
|
|
def test_gorefoot(self):
|
|
data = bytes.fromhex(
|
|
"10008000050475a7260ca7d38d420f3610018706103c7cb0800f81130118d41a426244f80f"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(item.stats[6].id, 140) # Extra Blood special stat
|
|
|
|
def test_byte_alignment(self):
|
|
# Fix for issue involving e.g. Natalya's Shadow
|
|
data = bytes.fromhex(
|
|
"100880000500148a1be03d81e1ae0510a00f0986001f4cd1229c9b2f5e3100c286fc07"
|
|
)
|
|
|
|
data, _ = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
|
|
def test_affixes(self):
|
|
data = bytes.fromhex(
|
|
"1000800005d0f4aa09173a36bf0723542d351ae4236acbd27000c30201a1052810208cf1241b4c50fc07"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
|
|
req = item.requirements()
|
|
self.assertEqual(req["lvl"], 4)
|
|
# +8 stamina
|
|
self.assertAlmostEqual(lookup_affix(item.prefixes[0], True)["name"], "Rugged")
|
|
# 16% ed
|
|
self.assertAlmostEqual(lookup_affix(item.prefixes[1], True)["name"], "Sturdy")
|
|
# 10% fhr
|
|
self.assertAlmostEqual(
|
|
lookup_affix(item.suffixes[0], False)["name"], "of Balance"
|
|
)
|
|
# +1 dex
|
|
self.assertAlmostEqual(
|
|
lookup_affix(item.suffixes[1], False)["name"], "of Dexterity"
|
|
)
|
|
# Lightning bolt on hit
|
|
self.assertAlmostEqual(
|
|
lookup_affix(item.suffixes[2], False)["name"], "of Charged Shield"
|
|
)
|
|
|
|
def test_cathans_rule(self):
|
|
# Cathan's Rule: Only source of fire-max stat
|
|
data = bytes.fromhex(
|
|
"10008000050054c90448ad74276f910150448c180afc24ff1348fd3f212d85b415d25a48fb0f"
|
|
)
|
|
data, item = parse_item(data)
|
|
self.assertEqual(data, b"")
|
|
self.assertEqual(str(item.stats[0]), "+10 to Maximum Fire Damage")
|