KAZIK/tools/tests/check_presentation.py
Игорь Федосеев 24d66ddf0e feat: add startup briefing and entry music
Sequence studio, texture AI disclosure and MASM code comparison before arrival. Show a typed hall briefing after admission.

Start the jukebox at 50% user volume on hall entry. Apply positional gain before playback to avoid a full-volume startup burst.
2026-11-02 01:04:11 +03:00

81 lines
3.7 KiB
Python

"""Compile and verify real MASM startup pages and the post-admission briefing."""
import argparse
import hashlib
from pathlib import Path
import subprocess
import sys
from PIL import Image, ImageChops, ImageDraw
from check_artifacts import toolchain
ROOT = Path(__file__).resolve().parents[2]
OUT = ROOT/'build/scratch'
sys.path.insert(0,str(ROOT/'tools/generators'))
from make_presentation_text import TEXT
def snapshot_runtime():
return {p:hashlib.sha256(p.read_bytes()).digest()
for p in (ROOT/'runtime').rglob('*') if p.is_file()}
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--window',action='store_true')
args = parser.parse_args()
OUT.mkdir(parents=True,exist_ok=True)
# Prevent silent clipping of the Russian copy or a missing font character.
for name,text in TEXT.items():
assert all(len(line)<=39 for line in text.splitlines()),name
assert b'\x97' not in text.encode('cp1251'),name
before = snapshot_runtime()
ml,link = toolchain()
sdk = Path('C:/Program Files (x86)/Windows Kits/10/Lib')
lib = next(p/'um/x86' for p in sorted(sdk.iterdir(),reverse=True)
if (p/'um/x86/kernel32.lib').exists())
commands = [[ml,'/c','/coff','/Cp','/nologo','/I.','/DPRESENTATION_TEST=1',
'/Fobuild/scratch/presentation-test.obj','poker.asm'],
[link,'/nologo','/SUBSYSTEM:CONSOLE','/LIBPATH:'+str(lib),
'/OUT:build/scratch/presentation-test.exe','build/scratch/presentation-test.obj',
'kernel32.lib','winmm.lib','user32.lib','ws2_32.lib','gdi32.lib']]
if args.window:
commands[0].insert(1,'/DPRESENTATION_WINDOW_TEST=1')
try:
for command in commands:
subprocess.run(list(map(str,command)),cwd=ROOT,check=True,timeout=120)
result = subprocess.run([str(OUT/'presentation-test.exe')],cwd=ROOT,timeout=120)
assert result.returncode == 0,f'Native presentation check failed: {result.returncode:#x}'
finally:
assert before == snapshot_runtime(),'Test changed player saves'
frames=[]
for index in range(12):
raw = (OUT/f'presentation-{index:02}.bgra').read_bytes()
assert len(raw)==640*480*4
image=Image.frombytes('RGBA',(640,480),raw,'raw','BGRA').convert('RGB')
image.save(OUT/f'presentation-{index:02}.png')
frames.append(image)
assert len({im.tobytes() for im in frames})==len(frames),'Frozen/repeated presentation'
for index in (1,2):
assert len(frames[index].getcolors(640*480))>5,'Missing native text'
# Opening starts at screen centre and expands horizontally, then vertically.
for index in (3,4,5,6,7):
image=frames[index]
assert image.getpixel((320,240)) in ((62,231,216),(8,16,27),(220,75,155)),index
assert ImageChops.difference(frames[9],frames[11]).getbbox(),'Typewriter did not advance'
sheet=Image.new('RGB',(3*640,4*504),(8,12,20))
draw=ImageDraw.Draw(sheet)
for index,image in enumerate(frames):
x,y=index%3*640,index//3*504
sheet.paste(image,(x,y))
draw.text((x+12,y+484),f'Native ASM / {index:02}',fill='white')
sheet.save(OUT/'presentation-contact.png')
if args.window:
image=Image.frombytes('RGBA',(640,480),(OUT/'presentation-window.bgra').read_bytes(),'raw','BGRA')
image.convert('RGB').save(OUT/'presentation-window.png')
print('PASS: ordered startup, automatic/key/skip transitions, guest admission, '
'centred deployment, typewriter, input cleanup, 50% entry music, '
'MCI playback/volume, no modal restart, manual track/stop, unchanged saves/RNG/bank; '
'12 native captures'+('; 150 Win32 frames' if args.window else ''))
if __name__=='__main__':
main()