"""Offline cutout packing; all scene and lever behaviour lives in MASM.""" from pathlib import Path import struct from PIL import Image from pack_guest_cast import isolate ROOT = Path(__file__).resolve().parents[2] def save(name, cells, width, height): frames = [] for cell in cells: cell = isolate(cell) scale = min((width-12)/cell.width, (height-12)/cell.height) size = round(cell.width*scale),round(cell.height*scale) sprite = cell.resize(size,Image.Resampling.LANCZOS) sprite.putalpha(sprite.getchannel("A").point(lambda a: 255 if a >= 128 else 0)) frame = Image.new("RGBA",(width,height)) frame.alpha_composite(sprite,((width-size[0])//2,height-6-size[1])) frames.append(frame) raw = b"".join(frame.tobytes("raw","BGRA") for frame in frames) (ROOT/f"assets/animations/hall/{name}.bin").write_bytes( struct.pack("<4s4I",b"ANM1",width,height,len(frames),len(raw))+raw) return frames def main(): portal = Image.open(ROOT/"assets/sprites/hall/upper-portal-v2.png").convert("RGBA") cells = [portal.crop((c*512,r*512,(c+1)*512,(r+1)*512)) for r in range(3) for c in range(2)] save("upper-portal-v2",cells[:4],224,320) save("upper-levers-v2",cells[4:],128,224) sheet = Image.open(ROOT/"assets/sprites/hall/upper-furniture-v2.png").convert("RGBA") tables = [sheet.crop((0,0,768,512)),sheet.crop((768,0,1536,512))] save("upper-games-v2",tables,320,224) # The approved sheet places the bartender's head above the lower row line. bartender = sheet.crop((180,400,650,1024)) stool = sheet.crop((860,540,1160,1024)) save("upper-bar-v2",[bartender,stool],160,256) print("Packed two distinct game tables, full bartender/stool, portal and two lever states") if __name__ == "__main__": main()