"""Build and execute native MASM combat, renderer, progression and save checks.""" from pathlib import Path import argparse import hashlib import subprocess from PIL import Image from check_artifacts import toolchain ROOT = Path(__file__).resolve().parents[2] OUT = ROOT / 'build/scratch' def main(): parser = argparse.ArgumentParser() parser.add_argument('--window',action='store_true') options = parser.parse_args() OUT.mkdir(parents=True, exist_ok=True) before = {p: hashlib.sha256(p.read_bytes()).digest() for p in (ROOT/'runtime').rglob('*') if p.is_file()} 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.','/DHELL_FPS_TEST=1', '/Fobuild/scratch/hell-fps.obj','poker.asm'], [link,'/nologo','/SUBSYSTEM:CONSOLE','/LIBPATH:'+str(lib), '/OUT:build/scratch/hell-fps-test.exe','build/scratch/hell-fps.obj', 'kernel32.lib','winmm.lib','user32.lib','ws2_32.lib','gdi32.lib']] if options.window: commands[0].insert(1,'/DHELL_FPS_WINDOW_TEST=1') for command in commands: subprocess.run(list(map(str,command)),cwd=ROOT,check=True,timeout=120) try: result = subprocess.run([str(OUT/'hell-fps-test.exe')],cwd=OUT if options.window else ROOT,timeout=90) finally: assert before == {p: hashlib.sha256(p.read_bytes()).digest() for p in (ROOT/'runtime').rglob('*') if p.is_file()}, 'Test changed player saves' assert result.returncode == 0, f'Native test failed at stage/exception {result.returncode:#x}' for name in (('window',) if options.window else ('entry','court','portal','victory')): raw = (OUT/f'hell-{name}.bgra').read_bytes() assert len(raw) == 640*480*4 image = Image.frombytes('RGBA',(640,480),raw,'raw','BGRA').convert('RGB') image.save(OUT/f'hell-{name}.png') assert len(image.getcolors(640*480)) > 100, f'{name}: blank renderer' if options.window: print('PASS: real Win32 window, 120 presented frames, mouse-down/up events, firing, Mick Gordon playback, six SFX channels, clean return') return print('PASS: painting entrance, collision/LOS, multi-target seven-pellet shotgun, ' 'single-ray pistol, armour/death/retry, gates/secrets, ' '1050 AI ticks, finite-ammo boss fight with dodging, first-clear reward, ' 'native/preview save roundtrips, return, 4 native render captures') if __name__ == '__main__': main()