Files
cobblemon-survival-pack/tools/summons.py
T
claudeandClaude Opus 5.5 f7ea371862 Phase 9: crafted summons for the legendaries
Adrian, 2026-11-09: legendaries, mythicals, Ultra Beasts and Paradox Pokemon
come from crafted summons. 22 Sigils (Naganadel evolves from Poipole), one
item told apart by custom data, from world/summons.json through
tools/summons.py: late-game recipes in three tiers (Lv 70, 80, 90), each used
in a fitting zone. A summoned legend fights as a boss (area attacks by level
and type, arena 32, the Guardian's Ward) but can be caught; on capture it
loses every boss mark. One at a time within 96 blocks.

Quest book: a Legends chapter, one quest per Sigil (97 quests). JEI lists each
Sigil as its own item, and Island Drops says where a legend is summoned; drops
Cobblemon names but doesn't have (Ho-Oh's Sacred Ash) get no slot.

Self-tests every_implemented_pokemon_is_obtainable (spawn, fossil or Sigil for
every implemented species) and sigil_summons_a_catchable_legend. Self-tests
and the island check pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 13:03:50 +01:00

105 lines
4.4 KiB
Python

#!/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/<species>.json species, level, zone, read by the companion mod (summon/Summons.kt)
recipe/summon_<species>.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()