Skip to content

Instantly share code, notes, and snippets.

@Encritary
Created May 15, 2022 10:33
Show Gist options
  • Save Encritary/7c6615e6f46e13d6da7efc1fdc6f67d5 to your computer and use it in GitHub Desktop.
Save Encritary/7c6615e6f46e13d6da7efc1fdc6f67d5 to your computer and use it in GitHub Desktop.
Artifact command generation for Grasscutter by entering stats
import json, itertools, sys
ARTIFACT_PATH = "resources/ExcelBinOutput/ReliquaryExcelConfigData.json"
MAINSTAT_PATH = "resources/ExcelBinOutput/ReliquaryMainPropExcelConfigData.json"
AFFIX_PATH = "resources/ExcelBinOutput/ReliquaryAffixExcelConfigData.json"
EQUIP_TYPES = {
"EQUIP_BRACER": "flower",
"EQUIP_NECKLACE": "plume",
"EQUIP_SHOES": "sands",
"EQUIP_RING": "goblet",
"EQUIP_DRESS": "circlet"
}
STATS = {
"hp": "FIGHT_PROP_HP",
"hp%": "FIGHT_PROP_HP_PERCENT",
"atk": "FIGHT_PROP_ATTACK",
"atk%": "FIGHT_PROP_ATTACK_PERCENT",
"def": "FIGHT_PROP_DEFENSE",
"def%": "FIGHT_PROP_DEFENSE_PERCENT",
"er": "FIGHT_PROP_CHARGE_EFFICIENCY",
"em": "FIGHT_PROP_ELEMENT_MASTERY",
"hb": "FIGHT_PROP_HEAL_ADD",
"cdmg": "FIGHT_PROP_CRITICAL_HURT",
"cr": "FIGHT_PROP_CRITICAL",
"phys%": "FIGHT_PROP_PHYSICAL_ADD_HURT",
"dendro%": "FIGHT_PROP_GRASS_ADD_HURT",
"geo%": "FIGHT_PROP_ROCK_ADD_HURT",
"anemo%": "FIGHT_PROP_WIND_ADD_HURT",
"hydro%": "FIGHT_PROP_WATER_ADD_HURT",
"cryo%": "FIGHT_PROP_ICE_ADD_HURT",
"electro%": "FIGHT_PROP_ELEC_ADD_HURT",
"pyro%": "FIGHT_PROP_FIRE_ADD_HURT"
}
with open(ARTIFACT_PATH, "r") as f:
artifactData = json.load(f)
with open(MAINSTAT_PATH, "r") as f:
mainStatData = json.load(f)
with open(AFFIX_PATH, "r") as f:
affixData = json.load(f)
inp = None
if len(sys.argv) == 2:
inp = open(sys.argv[1], "r")
input = lambda *args: inp.readline().rstrip()
elif len(sys.argv) > 2:
print("Usage: python3 artifact.py [artifact file]")
exit(1)
itemId = input("Artifact item ID: ")
if not itemId.isnumeric():
print("Artifact item ID must be numeric")
exit(1)
itemId = int(itemId)
item = None
for it in artifactData:
if it["Id"] == itemId:
item = it
break
else:
print("Unknown artifact item ID")
exit(1)
print("Artifact rarity:", str(item["RankLevel"]) + "*")
print("Artifact type:", EQUIP_TYPES[item["EquipType"]])
level = input("Level (0-" + str(item["MaxLevel"] - 1) + "): ")
if not level.isnumeric():
print("Level must be numeric")
exit(1)
level = int(level)+1
if not (1 <= level <= item["MaxLevel"]):
print("Level must be from 0 to", item["MaxLevel"]-1)
exit(1)
mainStat = input("Main stat: ")
if mainStat not in STATS:
print("Unknown main stat:" + mainStat + ". Available:", ", ".join(STATS.keys()))
exit(1)
mainStat = STATS[mainStat]
maxPropDepotId = -1
mainStatID = -1
for cand in mainStatData:
if cand["PropType"] == mainStat and cand["PropDepotId"] <= item["MainPropDepotId"] and cand["PropDepotId"] >= maxPropDepotId:
maxPropDepotId = cand["PropDepotId"]
mainStatID = cand["Id"]
if mainStatID == -1:
print("Couldn't find main stat")
exit(1)
result = "giveart " + str(itemId) + " " + str(mainStatID)
maxSubStatRolls = len(item["AddPropLevels"]) + 1
subStatArgs = []
if inp is None:
print("Sub stats:")
line = input()
cnt = 0
while line != "":
cnt += 1
if cnt > item["AppendPropNum"]:
print("Too many sub stats. Max:", item["AppendPropNum"])
exit(1)
statName, valueStr = line.split()
if statName not in STATS:
print("Unknown stat:" + statName + ". Available:", ", ".join(STATS.keys()))
exit(1)
if not valueStr.replace(".", "", 1).isnumeric():
print("Stat value must be a positive real number")
exit(1)
value = float(valueStr)
if (statName in ["cr", "cdmg", "er"] or statName[-1] == "%") and value > 1.0:
value /= 100.0
cands = []
for cand in affixData:
if cand["Weight"] > 150: # Test value
continue
if cand["PropType"] != STATS[statName]:
continue
if cand["DepotId"] != item["RankLevel"] * 100 + 1:
continue
cands.append(cand)
minDiff = float('inf')
bestGuess = None
for guess in itertools.product(range(maxSubStatRolls+1), repeat=len(cands)):
if sum(guess) > maxSubStatRolls:
continue
guessVal = 0.0
for i, n in enumerate(guess):
guessVal += cands[i]["PropValue"] * n
if abs(value-guessVal) < minDiff:
minDiff = abs(value-guessVal)
bestGuess = guess
if bestGuess is None:
print("Couldn't guess correct artifact sub stat value")
exit(1)
for i, n in enumerate(bestGuess):
if n > 0:
subStatArgs.append(str(cands[i]["Id"]) + "," + str(n))
if cnt == item["AppendPropNum"]:
line = ""
else:
line = input()
if len(subStatArgs) > 0:
result += " " + " ".join(subStatArgs)
result += " " + str(level)
print(result)
if inp is not None:
inp.close()
@Encritary
Copy link
Author

File input example:

23551
20
phys%
def 42
cr 3.9
cdmg 20.2
atk% 8.7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment