#!/usr/bin/env python3 """Write the crafted summons (Phase 9; Adrian, 2026-11-09) from world/summons.json. Legendaries, mythicals, Ultra Beasts and Paradox Pokémon have no spawn data, so each gets a Sigil (one item, cobblesurvival:summon_sigil, told apart by its custom data), used in a fitting zone to summon a catchable wild one. This writes, under datapacks/core/data/cobblesurvival/: summons/.json species, level, zone, read by the companion mod (summon/Summons.kt) recipe/summon_.json material in the corners, ring on the sides, core in the middle; the result carries the species, its name and where to use it, so the client needs no server data and the sigil's texture and item model in the companion mod. The fights are written by tools/zone_bosses.py, so run that afterwards, and tools/jei_sources.py and tools/quests.py after it. Needs the Cobblemon jar in build/server/mods (any test-server run), for the names. Usage: tools/summons.py """ import json import re import zipfile from pathlib import Path from PIL import Image ROOT = Path(__file__).resolve().parent.parent DATA = ROOT / "datapacks/core/data/cobblesurvival" ASSETS = ROOT / "mod/src/main/resources/assets/cobblesurvival" SIGIL = "cobblesurvival:summon_sigil" # The sigil: a dark disc with a gold ring and a violet eye. TEXTURE = [ "................", ".....######.....", "...##gggggg##...", "..#gg......gg#..", "..#g..vvvv..g#..", ".#g..vv++vv..g#.", ".#g.vv++++vv.g#.", ".#g.vv+WW+vv.g#.", ".#g.vv+WW+vv.g#.", ".#g.vv++++vv.g#.", ".#g..vv++vv..g#.", "..#g..vvvv..g#..", "..#gg......gg#..", "...##gggggg##...", ".....######.....", "................", ] COLORS = {"#": (40, 30, 60, 255), "g": (230, 185, 70, 255), ".": (0, 0, 0, 0), "v": (130, 60, 200, 255), "+": (190, 120, 245, 255), "W": (250, 235, 255, 255)} def names(jar): found = {} with zipfile.ZipFile(jar) as z: for name in z.namelist(): m = re.fullmatch(r"data/cobblemon/species/[^/]+/([^/]+)\.json", name) if m: found[m[1]] = json.loads(z.read(name))["name"] return found def main(): table = json.loads((ROOT / "world/summons.json").read_text()) plan = json.loads((ROOT / "world/zones.json").read_text()) zones = {z["id"]: z["name"] for z in plan["zones"] + plan["caves"] + plan.get("dimensions", [])} species_names = names(next((ROOT / "build/server/mods").glob("Cobblemon-*.jar"))) summons, recipes = DATA / "summons", DATA / "recipe" summons.mkdir(parents=True, exist_ok=True) for old in list(summons.glob("*.json")) + list(recipes.glob("summon_*.json")): old.unlink() comment = "Generated by tools/summons.py from world/summons.json; do not edit by hand." for species, s in table["summons"].items(): tier = table["tiers"][str(s["tier"])] name = species_names[species] (summons / f"{species}.json").write_text(json.dumps( {"_comment": comment, "species": species, "level": tier["level"], "zone": s["zone"]}, indent=1) + "\n") lore = f"Use in {zones[s['zone']]} to summon a Lv {tier['level']} {name}" (recipes / f"summon_{species}.json").write_text(json.dumps({ "_comment": comment, "type": "minecraft:crafting_shaped", "category": "misc", "pattern": ["MRM", "RCR", "MRM"], "key": {"M": {"item": s["material"]}, "R": {"item": tier["ring"]}, "C": {"item": tier["core"]}}, "result": {"id": SIGIL, "count": 1, "components": { "minecraft:custom_data": {"cobblesurvival_summon": species}, "minecraft:item_name": json.dumps(f"{name} Sigil"), "minecraft:lore": [json.dumps({"text": lore, "color": "gray", "italic": False})], }}, }, indent=1) + "\n") image = Image.new("RGBA", (16, 16)) for y, row in enumerate(TEXTURE): for x, c in enumerate(row): image.putpixel((x, y), COLORS[c]) (ASSETS / "textures/item").mkdir(parents=True, exist_ok=True) image.save(ASSETS / "textures/item/summon_sigil.png") (ASSETS / "models/item/summon_sigil.json").write_text(json.dumps( {"parent": "minecraft:item/generated", "textures": {"layer0": "cobblesurvival:item/summon_sigil"}}, indent=2) + "\n") print(f"wrote {len(table['summons'])} summons") if __name__ == "__main__": main()