Switch from affixes.json to stats.json

This commit is contained in:
2023-10-23 16:19:49 +02:00
parent b72166be0b
commit f6bfad2d4b
3 changed files with 73 additions and 291 deletions

View File

@@ -1,215 +0,0 @@
{
"0": {"bits": [8], "bias": 32, "text": "+{0} to Strength"},
"1": {"bits": [7], "bias": 32, "text": "+{0} to Energy"},
"2": {"bits": [7], "bias": 32, "text": "+{0} to Dexterity"},
"3": {"bits": [7], "bias": 32, "text": "+{0} to Vitality"},
"7": {"bits": [9], "bias": 32, "text": "+{0} to Life"},
"9": {"bits": [8], "bias": 32, "text": "+{0} to Mana"},
"11": {"bits": [8], "bias": 32, "text": "+{0} to Maximum Stamina"},
"16": {"bits": [9], "bias": 0, "text": "+{0}% Enhanced Defense"},
"17": {"bits": [9, 9], "bias": 0, "text": "+{0}% Enhanced Damage"},
"19": {"bits": [10], "bias": 0, "text": "+{0} to Attack rating"},
"20": {"bits": [6], "bias": 0, "text": "+{0}% Increased chance of blocking"},
"21": {"bits": [6], "bias": 0, "text": "+{0} to Minimum 1-handed damage"},
"22": {"bits": [7], "bias": 0, "text": "+{0} to Maximum 1-handed damage"},
"23": {"bits": [6], "bias": 0, "text": "+{0} to Minimum 2-handed damage"},
"24": {"bits": [7], "bias": 0, "text": "+{0} to Maximum 2-handed damage"},
"25": {"bits": [8], "bias": 0, "text": "Unknown (Invisible)"},
"26": {"bits": [8], "bias": 0, "text": "Unknown (Invisible)"},
"27": {"bits": [8], "bias": 0, "text": "Regenerate Mana {0}%"},
"28": {"bits": [8], "bias": 0, "text": "Heal Stamina {0}%"},
"31": {"bits": [11], "bias": 10, "text": "+{0} Defense"},
"32": {"bits": [9], "bias": 0, "text": "+{0} vs. Missile"},
"33": {"bits": [8], "bias": 10, "text": "+{0} vs. Melee"},
"34": {"bits": [6], "bias": 0, "text": "Damage Reduced by {0}"},
"35": {"bits": [6], "bias": 0, "text": "Magic Damage Reduced by {0}"},
"36": {"bits": [8], "bias": 0, "text": "Damage Reduced by {0}%"},
"37": {"bits": [8], "bias": 0, "text": "Magic Resist +{0}%"},
"38": {"bits": [8], "bias": 0, "text": "+{0}% to Maximum Magic Resist"},
"39": {"bits": [8], "bias": 50, "text": "Fire Resist +{0}%"},
"40": {"bits": [5], "bias": 0, "text": "+{0}% to Maximum Fire Resist"},
"41": {"bits": [8], "bias": 50, "text": "Lightning Resist +{0}%"},
"42": {"bits": [5], "bias": 0, "text": "+{0}% to Maximum Lightning Resist"},
"43": {"bits": [9], "bias": 200, "text": "Cold Resist +{0}%"},
"44": {"bits": [5], "bias": 0, "text": "+{0}% to Maximum Cold Resist"},
"45": {"bits": [8], "bias": 50, "text": "Poison Resist +{0}%"},
"46": {"bits": [5], "bias": 0, "text": "+{0}% to Maximum Poison Resist"},
"48": {"bits": [8, 9], "bias": 0, "text": "Adds {0}-{1} Fire Damage"},
"49": {"bits": [9], "bias": 0, "text": "+{0} to Maximum Fire Damage"},
"50": {"bits": [6, 10], "bias": 0, "text": "Adds {0}-{1} Lightning Damage"},
"52": {"bits": [8, 9], "bias": 0, "text": "Adds {0}-{1} Magic Damage"},
"54": {"bits": [8, 9, 8], "bias": 0, "text": "Adds {0}-{1} Cold Damage"},
"57": {"bits": [10, 10, 9], "bias": 0, "text": "Adds {0}-{1} Poison Damage over {2} Seconds"},
"60": {"bits": [7], "bias": 0, "text": "{0}% Life Stolen Per Hit"},
"62": {"bits": [7], "bias": 0, "text": "{0}% Mana Stolen Per Hit"},
"67": {"bits": [7], "bias": 30, "text": "Unknown (Invisible)"},
"68": {"bits": [7], "bias": 30, "text": "Unknown (Invisible)"},
"71": {"bits": [8], "bias": 100, "text": "Unknown (Invisible)"},
"72": {"bits": [9], "bias": 0, "text": "Unknown (Invisible)"},
"73": {"bits": [8], "bias": 0, "text": "+{0} Maximum Durability"},
"74": {"bits": [6], "bias": 30, "text": "Replenish Life +{0}"},
"75": {"bits": [7], "bias": 20, "text": "Increase Maximum Durability {0}%"},
"76": {"bits": [6], "bias": 10, "text": "Increase Maximum Life {0}%"},
"77": {"bits": [6], "bias": 10, "text": "Increase Maximum Mana {0}%"},
"78": {"bits": [7], "bias": 0, "text": "Attacker Takes Damage of {0}"},
"79": {"bits": [9], "bias": 100, "text": "{0}% Extra Gold from Monsters"},
"80": {"bits": [8], "bias": 100, "text": "{0}% Better Chance of Getting Magic Items"},
"81": {"bits": [7], "bias": 0, "text": "Knockback"},
"82": {"bits": [9], "bias": 20, "text": "Unknown (Invisible)"},
"83": {"bits": [3, 3], "bias": 0, "text": "+{1} to {0} Skill Levels"},
"84": {"bits": [3, 3], "bias": 0, "text": "+{1} to {0} Skill Levels"},
"85": {"bits": [9], "bias": 50, "text": "{0}% To Experience Gained"},
"86": {"bits": [7], "bias": 0, "text": "+{0} Life After Each Kill"},
"87": {"bits": [7], "bias": 0, "text": "Reduces Prices {0}%"},
"88": {"bits": [1], "bias": 0, "text": "Unknown (Invisible)"},
"89": {"bits": [4], "bias": 4, "text": "+{0} to Light Radius"},
"90": {"bits": [5], "bias": 0, "text": "Ambient light"},
"91": {"bits": [8], "bias": 100, "text": "Requirements {0}%"},
"92": {"bits": [7], "bias": 0, "text": "Level requirements +{0} (Invisible)"},
"93": {"bits": [7], "bias": 20, "text": "{0}% Increased Attack Speed"},
"94": {"bits": [7], "bias": 64, "text": "Unknown (Invisible)"},
"96": {"bits": [7], "bias": 20, "text": "{0}% Faster Run/Walk"},
"97": {"bits": [9, 6], "bias": 0, "text": "+{1} To {0}"},
"98": {"bits": [8, 1], "bias": 0, "text": "{1}+ to {0} (Visual effect only)"},
"99": {"bits": [7], "bias": 20, "text": "{0}% Faster Hit Recovery"},
"102": {"bits": [7], "bias": 20, "text": "{0}% Faster Block Rate"},
"105": {"bits": [7], "bias": 20, "text": "{0}% Faster Cast Rate"},
"107": {"bits": [9, 3], "bias": 0, "text": "+{1} To {0}"},
"108": {"bits": [1], "bias": 0, "text": "Rest In Peace"},
"109": {"bits": [9], "bias": 0, "text": "Unknown (Invisible)"},
"181": {"bits": [9, 5], "bias": 0, "text": "+{1} to spell {0} (char_class Only)"},
"182": {"bits": [9, 5], "bias": 0, "text": "+{1} to spell {0} (char_class Only)"},
"183": {"bits": [9, 5], "bias": 0, "text": "+{1} to spell {0} (char_class Only)"},
"184": {"bits": [9, 5], "bias": 0, "text": "+{1} to spell {0} (char_class Only)"},
"185": {"bits": [9, 5], "bias": 0, "text": "+{1} to spell {0} (char_class Only)"},
"186": {"bits": [9, 5], "bias": 0, "text": "+{1} to spell {0} (char_class Only)"},
"187": {"bits": [9, 5], "bias": 0, "text": "+{1} to spell {0} (char_class Only)"},
"110": {"bits": [8], "bias": 20, "text": "Poison Length Reduced by {0}%"},
"111": {"bits": [9], "bias": 20, "text": "Damage +{0}"},
"112": {"bits": [7], "bias": 0, "text": "Hit Causes Monsters to Flee {0}%"},
"113": {"bits": [7], "bias": 0, "text": "Hit Blinds Target +{0}"},
"114": {"bits": [6], "bias": 0, "text": "{0}% Damage Taken Goes to Mana"},
"115": {"bits": [1], "bias": 0, "text": "Ignore Target Defense"},
"116": {"bits": [7], "bias": 0, "text": "{0}% Target Defense"},
"117": {"bits": [7], "bias": 0, "text": "Prevent Monster Heal"},
"118": {"bits": [1], "bias": 0, "text": "Half Freeze Duration"},
"119": {"bits": [9], "bias": 20, "text": "{0}% Bonus to Attack Rating"},
"120": {"bits": [7], "bias": 128, "text": "{0} to Monster Defense Per Hit"},
"121": {"bits": [9], "bias": 20, "text": "+{0}% Damage to Demons"},
"122": {"bits": [9], "bias": 20, "text": "+{0}% Damage to Undead"},
"123": {"bits": [10], "bias": 128, "text": "+{0} to Attack Rating against Demons"},
"124": {"bits": [10], "bias": 128, "text": "+{0} to Attack Rating against Undead"},
"125": {"bits": [1], "bias": 0, "text": "Throwable"},
"126": {"bits": [3, 3], "bias": 0, "text": "+{0} to Fire Skills"},
"127": {"bits": [3], "bias": 0, "text": "+{0} to All Skill Levels"},
"128": {"bits": [5], "bias": 0, "text": "Attacker Takes Lightning Damage of {0}"},
"134": {"bits": [5], "bias": 0, "text": "Freezes Target +{0}"},
"135": {"bits": [7], "bias": 0, "text": "{0}% Chance of Open Wounds"},
"136": {"bits": [7], "bias": 0, "text": "{0}% Chance of Crushing Blow"},
"137": {"bits": [7], "bias": 0, "text": "+{0} Kick Damage"},
"138": {"bits": [7], "bias": 0, "text": "+{0} to Mana After Each Kill"},
"139": {"bits": [7], "bias": 0, "text": "+{0} Life after each Demon Kill"},
"140": {"bits": [7], "bias": 0, "text": "Extra Blood (Invisible)"},
"141": {"bits": [7], "bias": 0, "text": "{0}% Deadly Strike"},
"142": {"bits": [7], "bias": 0, "text": "Fire Absorb {0}%"},
"143": {"bits": [7], "bias": 0, "text": "+{0} Fire Absorb"},
"144": {"bits": [7], "bias": 0, "text": "Lightning Absorb {0}%"},
"145": {"bits": [7], "bias": 0, "text": "+{0} Lightning Absorb"},
"146": {"bits": [7], "bias": 0, "text": "Magic Absorb {0}%"},
"147": {"bits": [7], "bias": 0, "text": "+{0} Magic Absorb"},
"148": {"bits": [7], "bias": 0, "text": "Cold Absorb {0}%"},
"149": {"bits": [7], "bias": 0, "text": "+{0} Cold Absorb"},
"150": {"bits": [7], "bias": 0, "text": "Slows Target by {0}%"},
"151": {"bits": [9, 5], "bias": 0, "text": "Level +{1} {0} When Equipped"},
"152": {"bits": [1], "bias": 0, "text": "Indestructible"},
"153": {"bits": [1], "bias": 0, "text": "Cannot Be Frozen"},
"154": {"bits": [7], "bias": 20, "text": "{0}% Slower Stamina Drain"},
"155": {"bits": [10, 7], "bias": 0, "text": "{0}% Chance to Reanimate Target"},
"156": {"bits": [7], "bias": 0, "text": "Piercing Attack"},
"157": {"bits": [7], "bias": 0, "text": "Fires Magic Arrows"},
"158": {"bits": [7], "bias": 0, "text": "Fires Explosive Arrows or Bolts"},
"159": {"bits": [6], "bias": 0, "text": "+{0} to Minimum Throw Damage"},
"160": {"bits": [7], "bias": 0, "text": "+{0} to Maximum Throw Damage"},
"179": {"bits": [3], "bias": 0, "text": "+{0} to Druid Skill Levels"},
"180": {"bits": [3], "bias": 0, "text": "+{0} to Assassin Skill Levels"},
"188": {"bits": [3, 13, 3], "bias": 0, "text": "+{2} to {0} Skills ({1} only)"},
"189": {"bits": [10, 9], "bias": 0, "text": "+{0} to {1} Skills (char_class Only)"},
"190": {"bits": [10, 9], "bias": 0, "text": "+{0} to {1} Skills (char_class Only)"},
"191": {"bits": [10, 9], "bias": 0, "text": "+{0} to {1} Skills (char_class Only)"},
"192": {"bits": [10, 9], "bias": 0, "text": "+{0} to {1} Skills (char_class Only)"},
"193": {"bits": [10, 9], "bias": 0, "text": "+{0} to {1} Skills (char_class Only)"},
"194": {"bits": [4], "bias": 0, "text": "Adds {0} extra sockets to the item"},
"195": {"bits": [6, 10, 7], "bias": 0, "text": "{2}% Chance to Cast Level {0} {1} When you die"},
"196": {"bits": [6, 10, 7], "bias": 0, "text": "{2}% Chance to Cast Level {0} {1} When you die"},
"197": {"bits": [6, 10, 7], "bias": 0, "text": "{2}% Chance to Cast Level {0} {1} When you die"},
"198": {"bits": [6, 10, 7], "bias": 0, "text": "{2}% Chance to Cast Level {0} {1} On Striking"},
"199": {"bits": [6, 10, 7], "bias": 0, "text": "{2}% Chance to Cast Level {0} {1} On Striking"},
"200": {"bits": [6, 10, 7], "bias": 0, "text": "{2}% Chance to Cast Level {0} {1} On Striking"},
"201": {"bits": [6, 10, 7], "bias": 0, "text": "{2}% Chance to Cast Level {0} {1} When Struck"},
"202": {"bits": [6, 10, 7], "bias": 0, "text": "{2}% Chance to Cast Level {0} {1} When Struck"},
"203": {"bits": [6, 10, 7], "bias": 0, "text": "{2}% Chance to Cast Level {0} {1} When Struck"},
"204": {"bits": [6, 10, 8, 8], "bias": 0, "text": "Level {0} {1} ({2}/{3} Charges)"},
"205": {"bits": [6, 10, 8, 8], "bias": 0, "text": "Level {0} {1} ({2}/{3} Charges)"},
"206": {"bits": [6, 10, 8, 8], "bias": 0, "text": "Level {0} {1} ({2}/{3} Charges)"},
"207": {"bits": [6, 10, 8, 8], "bias": 0, "text": "Level {0} {1} ({2}/{3} Charges)"},
"208": {"bits": [6, 10, 8, 8], "bias": 0, "text": "Level {0} {1} ({2}/{3} Charges)"},
"209": {"bits": [6, 10, 8, 8], "bias": 0, "text": "Level {0} {1} ({2}/{3} Charges)"},
"210": {"bits": [6, 10, 8, 8], "bias": 0, "text": "Level {0} {1} ({2}/{3} Charges)"},
"211": {"bits": [6, 10, 8, 8], "bias": 0, "text": "Level {0} {1} ({2}/{3} Charges)"},
"212": {"bits": [6, 10, 8, 8], "bias": 0, "text": "Level {0} {1} ({2}/{3} Charges)"},
"213": {"bits": [6, 10, 8, 8], "bias": 0, "text": "Level {0} {1} ({2}/{3} Charges)"},
"214": {"bits": [6], "bias": 0, "text": "+{0} to Defense (Based on Character Level)"},
"215": {"bits": [6], "bias": 0, "text": "{0}% Enhanced Defense (Based on Character Level)"},
"216": {"bits": [6], "bias": 0, "text": "+{0} to Life (Based on Character Level)"},
"217": {"bits": [6], "bias": 0, "text": "+{0} to Mana (Based on Character Level)"},
"218": {"bits": [6], "bias": 0, "text": "+{0} to Maximum Damage (Based on Character Level)"},
"219": {"bits": [6], "bias": 0, "text": "{0}% Enhanced Maximum Damage (Based on Character Level)"},
"220": {"bits": [6], "bias": 0, "text": "+{0} to Strength (Based on Character Level)"},
"221": {"bits": [6], "bias": 0, "text": "+{0} to Dexterity (Based on Character Level)"},
"222": {"bits": [6], "bias": 0, "text": "+{0} to Energy (Based on Character Level)"},
"223": {"bits": [6], "bias": 0, "text": "+{0} to Vitality (Based on Character Level)"},
"224": {"bits": [6], "bias": 0, "text": "+{0} to Attack Rating (Based on Character Level)"},
"225": {"bits": [6], "bias": 0, "text": "{0}% Bonus to Attack Rating (Based on Character Level)"},
"226": {"bits": [6], "bias": 0, "text": "+{0} Cold Damage (Based on Character Level)"},
"227": {"bits": [6], "bias": 0, "text": "+{0} Fire Damage (Based on Character Level)"},
"228": {"bits": [6], "bias": 0, "text": "+{0} Lightning Damage (Based on Character Level)"},
"229": {"bits": [6], "bias": 0, "text": "+{0} Poison Damage (Based on Character Level)"},
"230": {"bits": [6], "bias": 0, "text": "Cold Resist +{0}% (Based on Character Level)"},
"231": {"bits": [6], "bias": 0, "text": "Fire Resist +{0}% (Based on Character Level)"},
"232": {"bits": [6], "bias": 0, "text": "Lightning Resist +{0}% (Based on Character Level)"},
"233": {"bits": [6], "bias": 0, "text": "Poison Resist +{0}% (Based on Character Level)"},
"234": {"bits": [6], "bias": 0, "text": "+{0} Cold Absorb (Based on Character Level)"},
"235": {"bits": [6], "bias": 0, "text": "+{0} Fire Absorb (Based on Character Level)"},
"236": {"bits": [6], "bias": 0, "text": "+{0} Lightning Absorb (Based on Character Level)"},
"237": {"bits": [6], "bias": 0, "text": "{0} Poison Absorb (Based on Character Level)"},
"238": {"bits": [5], "bias": 0, "text": "Attacker Takes Damage of {0} (Based on Character Level)"},
"239": {"bits": [6], "bias": 0, "text": "{0}% Extra Gold from Monsters (Based on Character Level)"},
"240": {"bits": [6], "bias": 0, "text": "{0}% Better Chance of Getting Magic Items (Based on Character Level)"},
"241": {"bits": [6], "bias": 0, "text": "Heal Stamina Plus {0}% (Based on Character Level)"},
"242": {"bits": [6], "bias": 0, "text": "+{0} Maxmium Stamina (Based on Character Level)"},
"243": {"bits": [6], "bias": 0, "text": "{0}% Damage to Demons (Based on Character Level)"},
"244": {"bits": [6], "bias": 0, "text": "{0}% Damage to Undead (Based on Character Level)"},
"245": {"bits": [6], "bias": 0, "text": "+{0} to Attack Rating against Demons (Based on Character Level)"},
"246": {"bits": [6], "bias": 0, "text": "+{0} to Attack Rating against Undead (Based on Character Level)"},
"247": {"bits": [6], "bias": 0, "text": "{0}% Chance of Crushing Blow (Based on Character Level)"},
"248": {"bits": [6], "bias": 0, "text": "{0}% Chance of Open Wounds (Based on Character Level)"},
"249": {"bits": [6], "bias": 0, "text": "+{0} Kick Damage (Based on Character Level)"},
"250": {"bits": [6], "bias": 0, "text": "{0}% to Deadly Strike (Based on Character Level)"},
"252": {"bits": [6], "bias": 0, "text": "Repairs 1 Durability in {0} Seconds"},
"253": {"bits": [6], "bias": 0, "text": "Replenishes Quantity"},
"254": {"bits": [8], "bias": 0, "text": "Increased Stack Size"},
"305": {"bits": [8], "bias": 50, "text": "{0} Pierce Cold"},
"306": {"bits": [8], "bias": 50, "text": "{0} Pierce Fire"},
"307": {"bits": [8], "bias": 50, "text": "{0} Pierce Lightning"},
"308": {"bits": [8], "bias": 50, "text": "{0} Pierce Poision"},
"324": {"bits": [6], "bias": 0, "text": "Unknown (Invisible)"},
"329": {"bits": [9], "bias": 50, "text": "{0}% To Fire Skill Damage"},
"330": {"bits": [9], "bias": 50, "text": "{0}% To Lightning Skill Damage"},
"331": {"bits": [9], "bias": 50, "text": "{0}% To Cold Skill Damage"},
"332": {"bits": [9], "bias": 50, "text": "{0}% To Poison Skill Damage"},
"333": {"bits": [8], "bias": 0, "text": "-{0}% To Enemy Fire Resistance"},
"334": {"bits": [8], "bias": 0, "text": "-{0}% To Enemy Lightning Resistance"},
"335": {"bits": [8], "bias": 0, "text": "-{0}% To Enemy Cold Resistance"},
"336": {"bits": [8], "bias": 0, "text": "-{0}% To Enemy Poison Resistance"},
"356": {"bits": [2], "bias": 0, "text": "Quest Item Difficulty +{0} (Invisible)"}
}

View File

@@ -16,13 +16,14 @@
# Mercator. If not, see <https://www.gnu.org/licenses/>.
import json
import os
import re
from bitarray import bitarray
from dataclasses import dataclass
from enum import Enum
_data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")
_basetype_map = None
_affix_map = None
_stats_map = None
class Quality(Enum):
@@ -50,22 +51,19 @@ class LowQualityType(Enum):
@dataclass
class Affix:
name_id: int
stat_id: int | None = None # TODO: These 3 should probably not be optional
stat_values: list[int] | None = None
stat_text: str | None = None
class Stat:
id: int | None = None # TODO: These 3 should probably not be optional
values: list[int] | None = None
parameter: int | None = None
text: str | None = None
def print(self, indent=5):
# TODO: name lookup
if self.stat_text:
subst_text = self.stat_text
for i, val in enumerate(self.stat_values):
replace = "{" + str(i) + "}"
subst_text = subst_text.replace(replace, str(val))
else:
subst_text = "<No text>"
print(" " * indent, f"{hex(self.name_id)}: {subst_text}")
subst_text = self.text
for val in self.values:
subst_text = subst_text.replace("#", str(val), 1)
if self.parameter:
subst_text = re.sub("\[[^\]]*\]", str(self.parameter), subst_text, 1)
print(" " * indent, subst_text)
def txtbits(bits: bitarray) -> str:
@@ -93,8 +91,8 @@ class Item:
graphic: int | None = None
inherent: int | None = None
low_quality: LowQualityType | None = None
prefixes: list[Affix] | None = None
suffixes: list[Affix] | None = None
prefixes: list[int] | None = None
suffixes: list[int] | None = None
set_id: int | None = None
unique_id: int | None = None
nameword1: int | None = None
@@ -106,6 +104,7 @@ class Item:
max_durability: int | None = None
sockets: int | None = None
quantity: int | None = None
stats: list[Stat] | None = None
def print(self, indent=5, with_raw=False):
properties = []
@@ -129,13 +128,9 @@ class Item:
if self.quality:
print(" " * indent, self.quality)
if self.prefixes:
print(" " * indent, "Prefixes:")
for prefix in self.prefixes:
prefix.print(indent + 4)
print(" " * indent, "Prefixes:", self.prefixes)
if self.suffixes:
print(" " * indent, "Suffixes:")
for suffix in self.suffixes:
suffix.print(indent + 4)
print(" " * indent, "Suffixes:", self.suffixes)
if self.set_id:
print(" " * indent, f"Set Id: {self.set_id}") # TODO: name lookup
if self.unique_id:
@@ -155,6 +150,10 @@ class Item:
print(" " * indent, f"Num Sockets: {self.sockets}")
if self.quantity:
print(" " * indent, f"Quantity: {self.quantity}")
if self.stats:
print(" " * indent, "Stats:")
for stat in self.stats:
stat.print(indent + 4)
if with_raw:
print(" " * indent, "Raw Item Data:")
bits = bitarray(endian="little")
@@ -172,9 +171,9 @@ def lookup_basetype(code: str) -> dict:
return _basetype_map[code]
def lookup_affix(code: int) -> dict:
global _affix_map
if _affix_map is None:
with open(os.path.join(_data_path, "affixes.json")) as f:
_affix_map = json.load(f)
return _affix_map[str(code)]
def lookup_stat(id: int) -> dict:
global _stats_map
if _stats_map is None:
with open(os.path.join(_data_path, "stats.json")) as f:
_stats_map = json.load(f)
return _stats_map[str(id)]

View File

@@ -19,12 +19,12 @@ from bitarray import bitarray
from bitarray.util import ba2int
from d2warehouse.stash import Stash, StashTab
from d2warehouse.item import (
Affix,
Item,
LowQualityType,
Quality,
lookup_affix,
Stat,
lookup_basetype,
lookup_stat,
)
import d2warehouse.huffman as huffman
@@ -134,7 +134,6 @@ def parse_item(data: bytes) -> tuple[bytes, Item]:
raise UnsupportedItemError("Ear items are not supported")
simple_byte_sz = int((sockets_end + 7) / 8)
print("simple size", simple_byte_sz)
item = Item(
data[:simple_byte_sz],
is_identified,
@@ -185,10 +184,9 @@ def parse_item(data: bytes) -> tuple[bytes, Item]:
enchantments_end += itembase_end
extended_byte_size = int((enchantments_end + 7) / 8)
print("extended size", extended_byte_size)
item.raw_data = data[:]
return b"", item # TODO: properly return remaining data
item.raw_data = data[:extended_byte_size]
return data[extended_byte_size:], item
def parse_item_graphic(bits: bitarray) -> tuple[int | None, int]:
@@ -242,8 +240,8 @@ def parse_high_quality_data(bits: bitarray, item: Item) -> tuple[Item, int]:
def parse_magic_data(bits: bitarray, item: Item) -> tuple[Item, int]:
item.prefixes = [Affix(name_id=ba2int(bits[0:11]))]
item.suffixes = [Affix(name_id=ba2int(bits[11:22]))]
item.prefixes = [ba2int(bits[0:11])]
item.suffixes = [ba2int(bits[11:22])]
return item, 22
@@ -272,11 +270,11 @@ def parse_unique_data(bits: bitarray, item: Item) -> tuple[Item, int]:
return item, 12
def parse_affix(bits: bitarray) -> tuple[Affix | None, int]:
def parse_affix(bits: bitarray) -> tuple[int | None, int]:
if not bits[0]:
return None, 1
else:
return Affix(name_id=ba2int(bits[1:12])), 12
return ba2int(bits[1:12]), 12
def parse_runeword(bits: bitarray) -> tuple[int, int]:
@@ -302,10 +300,7 @@ def parse_basetype_data(bits: bitarray, item: Item) -> tuple[Item, int]:
if cls == "tome":
ptr += 5 # unknown field
# Unknown bit here, supposedly 96 bits of realm data?? follow if set
if bits[ptr : ptr + 1]:
print("Unknown bit set, realm data follows?")
# ptr += 96 -- doesnt seem right
# Unknown bit here
ptr += 1
if cls == "armor":
@@ -354,58 +349,61 @@ def parse_enchantments(bits: bitarray, item: Item) -> tuple[Item, int]:
else:
num_lists = 1
# TODO: One extra list for runewords?
if num_lists > 0:
item.stats = []
while num_lists > 0:
affixes, ptr = parse_enchantment_list(bits[ptr:])
stats, sz = parse_enchantment_list(bits[ptr:])
ptr += sz
num_lists -= 1
for i, affix in enumerate(affixes):
# TODO: this works for magic, rare & crafted. But set & unique items do not have
# names specified in the save data, but do instead need to be read from data files
# to know if the mod is prefix or suffix. For now we add them all to prefixes.
# TODO: Also note, that sets have lists of mods they get from the set. Which should go
# seperately (assuming they are in the data files when not equipped...?)
if item.quality in [Quality.UNIQUE, Quality.SET]:
item.prefixes.append(Affix(name_id=0))
mod = item.prefixes[-1]
else:
# TODO: Here we assume that they are the same ordering as previously
mod = (
item.prefixes[i]
if i < len(item.prefixes)
else item.suffixes[i - len(item.prefixes)]
)
mod.stat_id = affix.stat_id
mod.stat_values = affix.stat_values
mod.stat_text = affix.stat_text
item.stats.extend(stats)
return item, ptr
def parse_enchantment_list(bits: bitarray) -> tuple[list[Affix], int]:
ptr = 0 # what is all this data?
affixes = []
def parse_enchantment_list(bits: bitarray) -> tuple[list[Stat], int]:
ptr = 0
stats = []
while True:
id = ba2int(bits[ptr : ptr + 9])
ptr += 9
if id == 0x1FF:
break
print("id", id)
print("stat id", id)
affix = lookup_affix(id)
if id == 107:
print(id, 107, "remainind data:")
print(bits)
stat = lookup_stat(id)
values = []
for b in affix["bits"]:
print("bits", b)
param = None
if stat["save_param_bits"]:
param = ba2int(bits[ptr : ptr + stat["save_param_bits"]])
ptr += stat["save_param_bits"]
for b in stat["save_bits"]:
values.append(ba2int(bits[ptr : ptr + b]))
ptr += b
values = [v - affix["bias"] for v in values]
text = affix["text"]
values = [v - stat["save_add"] for v in values]
text = stat["text"]
affixes.append(Affix(name_id=0, stat_id=id, stat_values=values, stat_text=text))
stat = Stat(
id=id,
values=values,
parameter=param,
text=text,
)
return affixes, ptr
print("Stat:")
stat.print()
stats.append(stat)
return stats, ptr
def parse_items(data: bytes) -> list[Item]: