"""Register generated motion strips to rigid arch/pedestal anchors.""" from pathlib import Path import struct from PIL import Image, ImageDraw from pack_guest_cast import isolate ROOT = Path(__file__).resolve().parents[2] def cells(name, columns, rows): sheet = Image.open(ROOT/f"assets/sprites/hall/{name}.png").convert("RGBA") return [sheet.crop((c*sheet.width//columns,r*sheet.height//rows, (c+1)*sheet.width//columns,(r+1)*sheet.height//rows)) for r in range(rows) for c in range(columns)] def write(name, frames): w,h = frames[0].size 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",w,h,len(frames),len(raw))+raw) def anchored(source, width, height): bounds = [cell.getchannel("A").point(lambda a: 255 if a >=128 else 0).getbbox() for cell in source] box = min(b[0] for b in bounds),min(b[1] for b in bounds),max(b[2] for b in bounds),max(b[3] for b in bounds) scale = min((width-12)/(box[2]-box[0]),(height-12)/(box[3]-box[1])) size = round((box[2]-box[0])*scale),round((box[3]-box[1])*scale) result = [] for cell in source: sprite = cell.crop(box).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])) result.append(frame) return result def main(): source = [isolate(cell) for cell in cells("upper-portal-v3",3,4)] active = [] for cell in source: sprite = cell.resize((244,308),Image.Resampling.LANCZOS) sprite.putalpha(sprite.getchannel("A").point(lambda a: 255 if a >=128 else 0)) frame = Image.new("RGBA",(256,320)) frame.alpha_composite(sprite,(6,6)) active.append(frame) # Keep every rigid arch pixel identical; register only the generated vortex. aperture = Image.new("L",(256,320)) ImageDraw.Draw(aperture).polygon([(77,295),(77,145),(82,115),(99,94), (128,73),(157,94),(174,115),(179,145),(179,295)],fill=255) locked = [Image.composite(frame,active[0],aperture) for frame in active] old = (ROOT/"assets/animations/hall/upper-portal-v2.bin").read_bytes() inactive = Image.frombytes("RGBA",(224,320),old[20:20+224*320*4],"raw","BGRA") inactive = inactive.resize((256,320),Image.Resampling.LANCZOS) inactive = Image.composite(inactive,active[0],aperture) write("upper-portal-v3",[frame.resize((256,512),Image.Resampling.LANCZOS) for frame in [inactive,*locked]]) levers = anchored(cells("upper-levers-v3",3,2),128,224) write("upper-levers-v3",levers) braziers = anchored(cells("upper-braziers-v3",2,2),128,256) for frame in braziers[1:]: frame.paste(braziers[0].crop((0,100,128,256)),(0,100)) write("upper-braziers-v3",braziers) preview = Image.new("RGBA",(768,640),(20,22,23,255)) for i,frame in enumerate([inactive,locked[0],locked[5],*levers[:3]]): preview.alpha_composite(frame,((i%3)*256,(i//3)*320)) preview.save(ROOT/"build/upper-motion-preview.png") print("Packed 12 vortex phases plus inactive arch, six lever positions, four brazier phases") if __name__ == "__main__": main()