KAZIK/tools/tests/check_hall_frames.py
Artvasil09 3ad5bf4c9d Develop assembly-only casino scenes and native games
Add native Durak, poker, blackjack, roulette, Buckshot and billiards scenes with animation assets and regression tests. Improve arrival, city, hall, profiles, shops, audio and exit handling; remove the portable C game core and refresh shipping executables.
2026-10-08 22:39:19 +03:00

60 lines
3.1 KiB
Python

"""Visual checks on framebuffers produced by the native MASM test executable."""
import hashlib
import json
import struct
from pathlib import Path
from PIL import Image, ImageDraw
ROOT = Path(__file__).resolve().parents[2]
OUTPUT = ROOT / "build/actions"
def main():
packs = {"bartender-v4": (256, 256, 24), "props": (256, 256, 9),
"drink-v4": (256, 256, 21), "street-life-v4": (192, 320, 40),
"sign": (128, 128, 3), "city-detail": (256, 256, 16),
"room-materials": (128, 128, 12), "patrons": (192, 320, 16),
"room-materials-hd": (256, 256, 12), "architecture": (128, 128, 12),
"architecture-hd": (256, 256, 12), "architecture-props": (256, 256, 6)}
for name, expected in packs.items():
data = (ROOT / "assets/animations/hall" / (name + ".bin")).read_bytes()
magic, width, height, count, length = struct.unpack_from("<4s4I", data)
assert magic == b"ANM1" and (width, height, count) == expected
assert len(data) == 20 + length == 20 + width * height * 4 * count
if name in ("bartender-v4", "props", "drink-v4", "street-life-v4", "patrons", "architecture-props"):
hashes = set()
for index in range(count):
payload = data[20 + index * width * height * 4:20 + (index + 1) * width * height * 4]
frame = Image.frombytes("RGBA", (width, height), payload, "raw", "BGRA")
assert set(frame.getchannel("A").tobytes()) == {0, 255}
box = frame.getchannel("A").getbbox()
assert box and box[0] > 0 and box[2] < width, (name, index, box)
hashes.add(hashlib.sha256(payload).hexdigest())
assert len(hashes) == count
names = ["hall-overview", "hall-bar", "hall-bunker", "hall-stairs", "bar-drink",
"native-wheel", "native-pool", "city-guards-approach", "hall-dining",
"city-street-v4", "hall-cabaret-v4", "bar-highball-v4", "bar-cocktail-v4",
"bar-water-v4", "pool-scratch-v4", "pool-power-v4"]
sheet = Image.new("RGB", (1280, ((len(names) + 1) // 2) * 505), "#191c19")
draw = ImageDraw.Draw(sheet)
report = {}
for index, name in enumerate(names):
frame = Image.open(OUTPUT / (name + ".bmp")).convert("RGB")
assert frame.size == (640, 480)
colors = len(frame.getcolors(640 * 480))
assert colors > (15 if name.startswith(("native-", "pool-")) else 100), (name, colors)
report[name] = {"colors": colors, "sha256": hashlib.sha256(frame.tobytes()).hexdigest()}
frame.save(OUTPUT / (name + ".png"))
x, y = (index % 2) * 640, (index // 2) * 505
draw.text((x + 8, y + 5), name, fill="white")
sheet.paste(frame, (x, y + 25))
sheet.save(OUTPUT / "hall-contact-sheet.png")
(OUTPUT / "hall-qa.json").write_text(json.dumps(report, indent=2), encoding="utf-8")
assert len({report[name]["sha256"] for name in
("bar-highball-v4", "bar-cocktail-v4", "bar-water-v4")}) == 3
print("PASS: hall/street assets and sixteen native framebuffer snapshots; three distinct drinks")
if __name__ == "__main__":
main()