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.
131 lines
5.9 KiB
Python
131 lines
5.9 KiB
Python
"""Verification test suite for the Jukebox / Jackbox music system."""
|
|
import ctypes
|
|
from pathlib import Path
|
|
import re
|
|
import struct
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
def test_packed_assets():
|
|
world_bin = ROOT / "assets/animations/hall/jackbox-v1.bin"
|
|
ui_bin = ROOT / "assets/animations/hall/jackbox-ui-v1.bin"
|
|
|
|
assert world_bin.is_file(), f"Missing {world_bin}"
|
|
assert ui_bin.is_file(), f"Missing {ui_bin}"
|
|
|
|
# Check world bin header: ANM1, 256, 512, 3 frames
|
|
wdata = world_bin.read_bytes()
|
|
magic, w, h, frames, raw_len = struct.unpack("<4s4I", wdata[:20])
|
|
assert magic == b"ANM1", f"Bad magic: {magic}"
|
|
assert (w, h, frames) == (256, 512, 3), f"Bad dimensions: {w}x{h}, {frames} frames"
|
|
assert len(wdata) == 20 + raw_len == 20 + 256 * 512 * 4 * 3
|
|
print(f"[OK] jackbox-v1.bin verified: {frames} frames ({w}x{h}), {raw_len} bytes")
|
|
|
|
# Check UI bin header: ANM1, 640, 480, 1 frame
|
|
uidata = ui_bin.read_bytes()
|
|
magic, w, h, frames, raw_len = struct.unpack("<4s4I", uidata[:20])
|
|
assert magic == b"ANM1", f"Bad magic: {magic}"
|
|
assert (w, h, frames) == (640, 480, 1), f"Bad dimensions: {w}x{h}, {frames} frames"
|
|
assert len(uidata) == 20 + raw_len == 20 + 640 * 480 * 4
|
|
print(f"[OK] jackbox-ui-v1.bin verified: {frames} frame ({w}x{h}), {raw_len} bytes")
|
|
|
|
|
|
def test_audio_tracks():
|
|
data_inc = (ROOT / "src_graphics/jackbox_data.inc").read_bytes().decode("cp1251")
|
|
open_cmds = re.findall(r'open\s+"([^"]+)"\s+type\s+(\w+)\s+alias\s+jboxmusic', data_inc)
|
|
assert len(open_cmds) == 2, f"Expected 2 audio tracks, got {len(open_cmds)}"
|
|
for rel_path, media_type in open_cmds:
|
|
assert "assets\\music\\jackbox" in rel_path or "assets/music/jackbox" in rel_path, f"Track must be from jackbox directory: {rel_path}"
|
|
|
|
for rel_path, media_type in open_cmds:
|
|
full_path = ROOT / rel_path
|
|
assert full_path.is_file(), f"Audio file missing: {rel_path}"
|
|
# Test MCI open & close
|
|
cmd_open = f'open "{full_path}" type {media_type} alias testjbox'
|
|
err = ctypes.windll.winmm.mciSendStringW(cmd_open, None, 0, None)
|
|
assert err == 0, f"MCI failed to open {rel_path}: error {err}"
|
|
try:
|
|
length_buf = ctypes.create_unicode_buffer(64)
|
|
err = ctypes.windll.winmm.mciSendStringW("status testjbox length", length_buf, 64, None)
|
|
assert err == 0, f"MCI failed to query length of {rel_path}"
|
|
finally:
|
|
ctypes.windll.winmm.mciSendStringW("close testjbox", None, 0, None)
|
|
print(f"[OK] MCI verified track: {rel_path} ({media_type})")
|
|
|
|
|
|
def test_code_structure():
|
|
data_inc = (ROOT / "src_graphics/jackbox_data.inc").read_bytes().decode("cp1251")
|
|
code_inc = (ROOT / "src_graphics/jackbox.inc").read_bytes().decode("cp1251")
|
|
casino_inc = (ROOT / "casino3d.inc").read_bytes().decode("cp1251")
|
|
hall_inc = (ROOT / "src_graphics/hall_scene.inc").read_bytes().decode("cp1251")
|
|
world_inc = (ROOT / "src_graphics/world_dressing.inc").read_bytes().decode("cp1251")
|
|
city_inc = (ROOT / "src_graphics/city_bins.inc").read_bytes().decode("cp1251")
|
|
|
|
# Check constants
|
|
assert "MODE_JACKBOX equ 28" in data_inc
|
|
assert "INTERACT_JACKBOX equ 52" in data_inc
|
|
assert "JACKBOX_X equ FP_1*306/10" in data_inc
|
|
assert "JACKBOX_Y equ FP_1*235/10" in data_inc
|
|
assert "MATERIAL_JACKBOX_SIDE equ 121" in data_inc
|
|
assert "MATERIAL_JACKBOX_BACK equ 213" in data_inc
|
|
|
|
# Check procs
|
|
procs = [
|
|
"LoadJackboxArt3D", "FreeJackboxArt3D", "ResolveJackboxSurface3D",
|
|
"DrawJackboxCabinet3D", "RenderJackboxCabinet3D", "JackboxCanWalk3D",
|
|
"PlayJukeboxTrack3D", "StopJukeboxTrack3D", "BeginJackbox3D",
|
|
"HandleJackbox3D", "RenderJackbox3D",
|
|
"CalculateJukeboxFalloff", "UpdateJukeboxAudio3D",
|
|
"HandleJukeboxKeys3D", "RenderJukeboxVolumeHUD"
|
|
]
|
|
for p in procs:
|
|
assert f"{p} PROC" in code_inc, f"Missing proc: {p}"
|
|
|
|
# Check integrations
|
|
assert "include src_graphics\\jackbox_data.inc" in casino_inc
|
|
assert "include src_graphics\\jackbox.inc" in casino_inc
|
|
assert "MODE_JACKBOX" in casino_inc
|
|
assert "HandleJackbox3D" in casino_inc
|
|
assert "RenderJackbox3D" in casino_inc
|
|
assert "call HandleJukeboxKeys3D" in casino_inc
|
|
assert "call UpdateJukeboxAudio3D" in casino_inc
|
|
assert "call RenderJukeboxVolumeHUD" in casino_inc
|
|
assert "jboxUserVolume dd" in data_inc
|
|
assert "setaudio jboxmusic volume to" in data_inc
|
|
play_proc = code_inc.split("PlayJukeboxTrack3D PROC", 1)[1].split("PlayJukeboxTrack3D ENDP", 1)[0]
|
|
assert play_proc.index("call UpdateJukeboxAudio3D") < play_proc.index("OFFSET jboxPlayCmd"), "Set gain before playback"
|
|
arrival_inc = (ROOT / "src_graphics/arrival_scene.inc").read_bytes().decode("cp1251")
|
|
entry = arrival_inc.split("arrival_entry:", 1)[1].split("arrival_profile_input:", 1)[0]
|
|
assert entry.index("mov engineMode, MODE_WALK") < entry.index("mov jboxUserVolume, 5")
|
|
assert "invoke PlayJukeboxTrack3D, 0" in entry
|
|
|
|
assert "call LoadJackboxArt3D" in world_inc
|
|
assert "call FreeJackboxArt3D" in world_inc
|
|
assert "call RenderJackboxCabinet3D" in world_inc
|
|
|
|
assert "INTERACT_JACKBOX" in hall_inc
|
|
assert "BeginJackbox3D" in hall_inc
|
|
assert "JackboxCanWalk3D" in hall_inc
|
|
|
|
assert "ResolveJackboxSurface3D" in city_inc
|
|
print("[OK] Code structure and all integrations verified.")
|
|
|
|
|
|
def test_binary_executable():
|
|
exe_path = ROOT / "poker.exe"
|
|
assert exe_path.is_file()
|
|
exe_bytes = exe_path.read_bytes()
|
|
|
|
assert b"jackbox-v1.bin" in exe_bytes
|
|
assert b"jackbox-ui-v1.bin" in exe_bytes
|
|
assert b"jboxmusic" in exe_bytes
|
|
print(f"[OK] poker.exe verified with embedded Jackbox strings ({len(exe_bytes)} bytes).")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_packed_assets()
|
|
test_audio_tracks()
|
|
test_code_structure()
|
|
test_binary_executable()
|
|
print("\nALL JACKBOX / JUKEBOX VERIFICATION CHECKS PASSED!")
|