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.
81 lines
3.7 KiB
Python
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()
|