- Billiards: add native Russian Pyramid & American Eight-Ball pool with physics prediction, controls, and regression tests - Scratch Tickets: add dedicated counter, mat presentation, elliptical coin scraping, 4 ticket types, and payout effects - First-Person Dice: add native dice scene, hand anchor frames, throwing animation, and table perspective - City Wake & Weather: add arrival cutscene, alley geometry, weather/rain effects, and lighter/rocker animation - World Dressing: add hall paintings, furniture packs, hall lighting, and scene regression tests - Build & Tooling: update build.bat for modern MSVC toolchain, update launcher hash, and refresh shipping binaries
33 lines
1.3 KiB
Python
33 lines
1.3 KiB
Python
"""Offline packing only: wall paintings and a small iron drainage texture."""
|
|
from pathlib import Path
|
|
import struct
|
|
from PIL import Image
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
def main():
|
|
image = Image.open(ROOT/"assets/sprites/hall/wall-paintings-v6.png").convert("RGBA")
|
|
frames = []
|
|
for side in range(2):
|
|
part = image.crop((side*image.width//2,0,(side+1)*image.width//2,image.height))
|
|
mask = part.getchannel("A").point(lambda a:255 if a>=96 else 0)
|
|
part = part.crop(mask.getbbox()).resize((128,128),Image.Resampling.LANCZOS)
|
|
part.putalpha(part.getchannel("A").point(lambda a:255 if a>=128 else 0))
|
|
frames.append(part)
|
|
drain = Image.new("RGBA",(128,128),(51,55,57,255))
|
|
for y in range(128):
|
|
for x in range(128):
|
|
if 7<x<121 and 7<y<121:
|
|
value = 21 if x%16<10 else 68+(y%3)*3
|
|
else:
|
|
value = 78 if x<4 or y<4 else 40
|
|
drain.putpixel((x,y),(value,value+2,value+3,255))
|
|
frames.append(drain)
|
|
raw = b"".join(frame.tobytes("raw","BGRA") for frame in frames)
|
|
(ROOT/"assets/animations/hall/world-dressing-v6.bin").write_bytes(struct.pack("<4s4I",b"ANM1",128,128,3,len(raw))+raw)
|
|
print("Packed two framed wall paintings and one iron drainage material, 128x128 BGRA")
|
|
|
|
|
|
if __name__=="__main__":
|
|
main()
|