diff --git a/d2warehouse/contrib/stats.py b/d2warehouse/contrib/stats.py new file mode 100644 index 0000000..848e842 --- /dev/null +++ b/d2warehouse/contrib/stats.py @@ -0,0 +1,96 @@ +# Parse itemstatcost.txt and properties.txt into aggregated json. + +import csv +import json +import os +import sys + + +path = sys.argv[1] if len(sys.argv) >= 2 else "." + +# NOTE: These map "linked stats" to code in properties.txt. +# If None is given, the stat is excluded from the output. +# Note that All Resistance is actually 4 stats in the save files, that the game combines +# into one. Same applies for all stats. +special_stats = { + "firemindam": "dmg-fire", + "firemaxdam": None, + "lightmindam": "dmg-ltng", + "lightmaxdam": None, + "magicmindam": "dmg-mag", + "magicmaxdam": None, + "coldmindam": "dmg-cold", + "coldmaxdam": None, + "coldlength": None, + "poisonmindam": "dmg-pois", + "poisonmaxdam": None, + "poisonlength": None, + "mindamage": "dmg-norm", + "maxdamage": None, +} + +properties = {} +stat_to_prop = {} +with open(os.path.join(path, "properties.txt")) as f: + reader = csv.DictReader(f, delimiter="\t") + for row in reader: + if len(row["stat1"]) == 0 or len(row["*Tooltip"]) == 0: + continue + prop = { + "stats": [row[f"stat{i}"] for i in range(1, 8) if len(row[f"stat{i}"]) > 0], + "tooltip": row["*Tooltip"], + } + properties[row["code"]] = prop + if len(prop["stats"]) == 1 and prop["stats"][0] not in stat_to_prop: + stat_to_prop[prop["stats"][0]] = row["code"] + +itemstatcost = {} +with open(os.path.join(path, "itemstatcost.txt")) as f: + reader = csv.DictReader(f, delimiter="\t") + for row in reader: + itemstatcost[row["Stat"]] = { + "id": row["*ID"], + "save_bits": 0 if len(row["Save Bits"]) == 0 else int(row["Save Bits"]), + "save_add": 0 if len(row["Save Add"]) == 0 else int(row["Save Add"]), + "save_param_bits": None + if len(row["Save Param Bits"]) == 0 + else int(row["Save Param Bits"]), + } + +stats = {} +for stat, statdat in itemstatcost.items(): + if stat in special_stats: + if special_stats[stat] is None: + continue + else: + prop = properties[special_stats[stat]] + obj = { + "text": prop["tooltip"], + "save_bits": [], + "save_add": itemstatcost[prop["stats"][0]]["save_add"], + "save_param_bits": itemstatcost[prop["stats"][0]]["save_param_bits"], + } + for prop_stat in prop["stats"]: + if itemstatcost[prop_stat]["save_add"] != obj["save_add"]: + print( + f"Unexpected divergence in save_add for stats in prop {special_stats[stat]}" + ) + obj["save_bits"].append(itemstatcost[prop_stat]["save_bits"]) + else: + try: + prop = properties[stat_to_prop[stat]] + except KeyError: + print( + f"Failed getting property for stat {stat}. Skipping! (See `special_stats` for fixing)" + ) + continue + obj = { + "text": prop["tooltip"], + "save_bits": [statdat["save_bits"]], + "save_add": statdat["save_add"], + "save_param_bits": statdat["save_param_bits"], + } + stats[statdat["id"]] = obj + +with open("stats.json", "w", newline="\n") as f: + json.dump(stats, f, indent=4)