- workbench_bundles.py: each crafting press's CraftingWorkbenchDataComponent.recipeBundles resolved (full press = Armament T1+T2+Utility; small press = T1+Utility, no T2) - discord_recipes.py: Discord-formatted Tier1/Tier2 workbench + conveyor recipe tables
92 lines
3.3 KiB
Python
92 lines
3.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Emit Discord-ready (monospace code-block) tables of all craftable recipes:
|
|
the workbench recipes (T1 + T2, both on the Trampler; T2 also at world workbenches)
|
|
and the world conveyor production lines with their island locations.
|
|
"""
|
|
import json, collections
|
|
|
|
NAMES = json.load(open("extracted/item_names.json"))["items"]
|
|
REC = json.load(open("extracted/crafting_recipes.json"))["recipes"]
|
|
PL = json.load(open("extracted/production_lines.json"))["production_lines"]
|
|
PLACE = json.load(open("extracted/conveyor_placements.json"))
|
|
ISL = json.load(open("extracted/island_names.json"))["islands"]
|
|
|
|
|
|
def nm(item_id):
|
|
e = NAMES.get(item_id)
|
|
if e and e.get("name"):
|
|
return e["name"]
|
|
return item_id # fall back to raw id (no i2 term)
|
|
|
|
|
|
def fmt_side(ings):
|
|
# merge duplicate item slots (some recipes list the same id in two output slots)
|
|
merged = {}
|
|
order = []
|
|
for i in ings:
|
|
k = i["itemId"]
|
|
if k not in merged:
|
|
merged[k] = 0
|
|
order.append(k)
|
|
merged[k] += i["amount"]
|
|
return " + ".join("%d %s" % (merged[k], nm(k)) for k in order)
|
|
|
|
|
|
def table(rows, headers):
|
|
cols = list(zip(*([headers] + rows))) if rows else [[h] for h in headers]
|
|
w = [max(len(str(c)) for c in col) for col in cols]
|
|
line = lambda r: "| " + " | ".join(str(c).ljust(w[i]) for i, c in enumerate(r)) + " |"
|
|
sep = "|" + "|".join("-" * (w[i] + 2) for i in range(len(headers))) + "|"
|
|
out = [line(headers), sep] + [line(r) for r in rows]
|
|
return "\n".join(out)
|
|
|
|
|
|
def recipe_rows(keys):
|
|
rows = []
|
|
for key in keys:
|
|
for r in REC[key]:
|
|
rows.append([fmt_side(r["inputs"]), fmt_side(r["outputs"]), "%gs" % r["craftTimeSeconds"]])
|
|
return rows
|
|
|
|
|
|
# ---- island placement map: conveyor base name -> [in-game island names] ----
|
|
def island_disp(prefab):
|
|
d = ISL.get(prefab, {})
|
|
return d.get("toponym") or prefab.replace("island_", "")
|
|
|
|
|
|
conv_to_islands = collections.defaultdict(list)
|
|
for prefab, d in PLACE["islands"].items():
|
|
if prefab.startswith("island_test"):
|
|
continue
|
|
for rc in d["recipes"]:
|
|
conv_to_islands[rc["conveyor"]].append(island_disp(prefab))
|
|
for u in d["product_conveyors_without_matching_recipe"]:
|
|
# name-mismatch: singular placed instance maps to its plural recipe key
|
|
conv_to_islands[u["conveyor"] + "s"].append(island_disp(prefab))
|
|
|
|
OUT = []
|
|
OUT.append("## Workbench Crafts\n")
|
|
|
|
for title, keys in [("Tier 1", ["Recipes_Utility_Workbench_T1", "Recipes_Armament_Workbench_T1"]),
|
|
("Tier 2", ["Recipes_Armament_Workbench_T2"])]:
|
|
OUT.append("**%s**" % title)
|
|
OUT.append("```")
|
|
OUT.append(table(recipe_rows(keys), ["Inputs", "Output", "Time"]))
|
|
OUT.append("```")
|
|
|
|
OUT.append("\n## World Conveyor Production Lines (single-recipe, fixed locations)\n")
|
|
# the game_conveyor_base* lines are test-island stubs (placeholder recipes); skip them
|
|
rows = []
|
|
for conv, r in sorted(PL.items()):
|
|
if conv.startswith("game_conveyor_base"):
|
|
continue
|
|
islands = conv_to_islands.get(conv, [])
|
|
loc = ", ".join(sorted(set(islands))) if islands else "(defined, not placed)"
|
|
rows.append([fmt_side(r["inputs"]), fmt_side(r["outputs"]), "%gs" % r["craftTimeSeconds"], loc])
|
|
OUT.append("```")
|
|
OUT.append(table(rows, ["Inputs", "Output", "Time", "Location (island)"]))
|
|
OUT.append("```")
|
|
|
|
print("\n".join(OUT))
|