Files
mplus-routes/tools/check_kg_alignment.py
florian.berthold 18c7792935 switch to keystone.guru tiles + enemy data
Replaces the upreza-derived 4K dungeon textures + AtlasLoot boss-coord
overlay (which had a consistent positional offset against texture skulls)
with keystone.guru's z=4 tile pyramid stitched to 6144x4096 WebP per floor.

kg's split_floors.js gives per-dungeon enemies, packs (polygons), patrols
(polylines), and map icons calibrated to those tiles, so overlays align
pixel-perfectly. 27/29 classic dungeons now have full enemy/pack data;
ZG + Sunken Temple have maps only.

Pipeline: tools/kg_fetch.py -> tools/kg_stitch.py -> tools/kg_build_data.py.
2026-04-25 22:11:17 +02:00

60 lines
2.1 KiB
Python

#!/usr/bin/env python3
"""
Render every classic dungeon's first-floor webp with kg's enemy positions
overlaid as colored circles, plus pack polygon outlines, to verify alignment
visually. Output: /tmp/kg_alignment/<key>.png
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
from PIL import Image, ImageDraw
ROOT = Path(__file__).resolve().parent.parent
WEB_MAPS = ROOT / "web" / "assets" / "maps"
DUNGEONS_JSON = ROOT / "web" / "assets" / "dungeons.json"
OUT_DIR = Path("/tmp/kg_alignment")
CLASS_RADIUS = {1: 14, 2: 18, 3: 28, 4: 38}
CLASS_FILL = {1: "#9aa1aa", 2: "#d6d6dc", 3: "#d63b3b", 4: "#ffd83a"}
def main() -> int:
OUT_DIR.mkdir(parents=True, exist_ok=True)
data = json.loads(DUNGEONS_JSON.read_text())
rendered = []
for d in data["dungeons"]:
if not d["maps"]:
continue
m = d["maps"][0]
src = WEB_MAPS / Path(m["image"]).name
if not src.exists():
continue
with Image.open(src) as im:
im = im.convert("RGBA")
W, H = im.size
draw = ImageDraw.Draw(im)
for p in m.get("packs", []):
pts = [(int(x), int(y)) for x, y in p["vertices"]]
if len(pts) >= 3:
draw.polygon(pts, outline=p["color"], width=4)
for e in m.get("enemies", []):
cls = e.get("classification") or 1
r = CLASS_RADIUS.get(cls, 14)
fill = CLASS_FILL.get(cls, "#9aa1aa")
x, y = int(e["pos"][0]), int(e["pos"][1])
draw.ellipse([x - r, y - r, x + r, y + r], fill=fill, outline="black", width=3)
scale = 1024 / W
small = im.resize((1024, int(H * scale)), Image.LANCZOS)
out = OUT_DIR / f"{d['id']}.png"
small.save(out)
rendered.append((d["id"], d["name"], len(m.get("enemies", [])), len(m.get("packs", []))))
print(f"rendered {len(rendered)} dungeons → {OUT_DIR}")
for did, name, n_e, n_p in rendered:
print(f" {did:32s} enemies={n_e:4d} packs={n_p:3d}")
return 0
if __name__ == "__main__":
raise SystemExit(main())