18c7792935
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.
60 lines
2.1 KiB
Python
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())
|