forked from omicron/d2warehouse
Switch from affixes.json to stats.json
This commit is contained in:
@@ -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)"}
|
||||
}
|
||||
@@ -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)]
|
||||
|
||||
@@ -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]:
|
||||
|
||||
Reference in New Issue
Block a user