#!/usr/bin/env python3 """Genera GIFs placeholder paletitzats per al sistema d'entitats. Motor: el GIF loader del joc (source/core/rendering/gif.cpp) treballa amb GIFs paletitzats (mode P). Aquest script usa Pillow per crear un fitxer per entitat amb un únic frame de color sòlid distintiu, perquè cada entitat es distingeixi en pantalla en ausència d'art definitiu. Sortida: data/entities//.gif amb les mides especificades. Execució: python3 tools/entities/generate_placeholders.py """ from __future__ import annotations import os from pathlib import Path from PIL import Image # (width, height, (r,g,b)) per a cada entitat. L'ordre no importa. ENTITIES = { "torch": (16, 16, (255, 165, 0)), # taronja "door": (16, 16, (101, 67, 33)), # marró fosc "mummy": (12, 24, (235, 215, 180)), # beige "sarcophagus": (48, 16, (212, 175, 55)), # daurat (3×1 tiles) "rolling_rock": (16, 16, (128, 128, 128)), # gris "wall_trap": (16, 16, (139, 0, 0)), # vermell fosc "floor_trap": (16, 16, (220, 20, 60)), # vermell clar (crimson) } def build_gif(width: int, height: int, rgb: tuple[int, int, int]) -> Image.Image: """Crea un GIF paletitzat d'un sol frame amb color sòlid. Entrada 0 de la paleta = transparent (convenció del motor). El color del sprite viu a l'entrada 1; la resta de la paleta s'omple amb negre. Com que només usem un índex visible, l'LZW comprimeix el frame a una rajola de bytes idèntics. """ img = Image.new("P", (width, height), color=1) palette = bytearray(256 * 3) # Índex 0: transparent (valor RGB irrellevant; marcat amb transparency). palette[0:3] = bytes((0, 0, 0)) palette[3:6] = bytes(rgb) img.putpalette(bytes(palette)) return img def main() -> int: repo_root = Path(__file__).resolve().parents[2] base = repo_root / "data" / "entities" for name, (width, height, rgb) in ENTITIES.items(): out_dir = base / name out_dir.mkdir(parents=True, exist_ok=True) out_file = out_dir / f"{name}.gif" img = build_gif(width, height, rgb) # transparency=0 mantén la convenció del motor; optimize=False # força un GIF amb GCT estàndard (el loader no accepta variants # minimalistes sense GCT). img.save(out_file, format="GIF", transparency=0, optimize=False) size = os.path.getsize(out_file) print(f" {out_file.relative_to(repo_root)} {width}x{height} {size} bytes") print(f"OK: {len(ENTITIES)} placeholders escrits a data/entities/") return 0 if __name__ == "__main__": raise SystemExit(main())