"""Offline normalization only; scratch masks, input and prizes run in MASM.""" from pathlib import Path import json import struct from PIL import Image import pack_city_wake ROOT = Path(__file__).resolve().parents[2] SRC = ROOT / "assets/sprites/scratch" OUT = ROOT / "assets/animations/scratch" def opaque(image): image = image.convert("RGBA") image.putalpha(image.getchannel("A").point(lambda a: 255 if a >= 160 else 0)) return image def pack(name, frames): w,h = frames[0].size raw = b"".join(f.tobytes("raw","BGRA") for f in frames) (OUT / name).write_bytes(struct.pack("<4s4I",b"ANM1",w,h,len(frames),len(raw))+raw) def main(): OUT.mkdir(parents=True,exist_ok=True) table = Image.open(SRC / "table-v1.png").convert("RGBA").resize((640,480),Image.Resampling.NEAREST) table.putalpha(255) pack("table-v1.bin",[table]) tickets = [] for name in ("ticket-v1.png", "ticket-numbers-v1.png", "ticket-rows-v1.png", "ticket-instant-v1.png"): ticket = opaque(Image.open(SRC / name)) tickets.append(ticket.crop(ticket.getbbox()).resize((448,288),Image.Resampling.NEAREST)) pack("ticket-v1.bin",tickets) foil = Image.open(SRC / "foil-v1.png").convert("RGBA").resize((104,42),Image.Resampling.BOX) foil.putalpha(255) pack("foil-v1.bin",[foil]) pack_city_wake.SRC = SRC bodies = pack_city_wake.figures("coin-edge-v1.png",4) scale = min(48/max(b.width for b in bodies),56/max(b.height for b in bodies)) frames = [] for body in bodies: body = body.resize((round(body.width*scale),round(body.height*scale)),Image.Resampling.NEAREST) bottom = body.height-1 xs = [x for x in range(body.width) if body.getpixel((x,bottom))[3]] anchor = (min(xs)+max(xs))//2 frame = Image.new("RGBA",(64,64)) frame.paste(body,(32-anchor,60-bottom)) frames.append(frame) pack("coin-edge-v1.bin",frames) counter = opaque(Image.open(SRC / "counter-v1.png")) counter = counter.crop(counter.getbbox()) scale = min(224/counter.width,240/counter.height) counter = counter.resize((round(counter.width*scale),round(counter.height*scale)),Image.Resampling.NEAREST) frame = Image.new("RGBA",(224,240)) frame.paste(counter,((224-counter.width)//2,240-counter.height)) pack("counter-v1.bin",[frame]) for index,ticket in enumerate(tickets): ticket.save(ROOT / f"build/scratch/ticket-{index}-normalized.png") sheet = Image.new("RGBA",(256,64)) for i,frame in enumerate(frames): sheet.paste(frame,(64*i,0)) sheet.save(ROOT / "build/scratch/coin-normalized.png") print("Packed lottery paper, four edge-contact coins (hotspot 32,60), grounded ticket counter") if __name__ == "__main__": main()