"""Verify the native/legacy file mappings and Windows MCI decoders without playing audio.""" import ctypes from pathlib import Path import re ROOT = Path(__file__).resolve().parents[2] def asm_paths(): for file in [ROOT / "src_graphics/audio_data.inc", ROOT / "src_graphics/casino_actions_data.inc", ROOT / "src_graphics/scratch_data.inc"]: definitions = {} current = None for line in file.read_text(encoding="ascii").splitlines(): match = re.match(r"(\w+) db (.+)$", line) continuation = re.match(r"\s+db (.+)$", line) if match: current = match[1] definitions[current] = match[2] elif continuation and current: definitions[current] += "," + continuation[1] else: current = None for symbol, payload in definitions.items(): chunks = re.findall(r'"[^"]*"|\d+', payload) raw = b"".join(c[1:-1].encode("ascii") if c.startswith('"') else bytes([int(c)]) for c in chunks) name = raw.rstrip(b"\0").decode("cp1251") if name.endswith(".wav"): yield symbol, name def main(): native = dict(asm_paths()) assert native["soundCards"].endswith("playing_cards_deck_flick_through_001_20485.wav") assert native["soundCoin"].endswith("Звук монеты брошенной в воздух и упавшей на поверхность.wav") assert native["soundRoulette"].endswith("roulette-wheel-throw-2.wav") assert native["rrDrySound3D"].endswith("revolverdryfirec.wav") assert native["rrFireSound3D"].endswith("b05e1ac8be34248.wav") assert native["soundClick"] != native["rrDrySound3D"] assert native["soundDiceRoll"] != native["soundCards"] assert len({native[name] for name in ("scrScrapeSound3D","scrPaperSound3D","scrPayoutSound3D")})==3 engine = (ROOT / "casino3d.inc").read_text(encoding="cp1251") assert "invoke PlaySoundA, OFFSET sound" not in engine if "LaunchClassicGame PROC" in engine: assert "call InitSounds" in engine.split("run_game_body:")[1].split("LaunchClassicGame ENDP")[0] else: # Native-only builds intentionally removed the terminal launch path. assert "run_game_body:" not in engine assert "invoke PlayCasinoSound3D, OFFSET soundDiceRoll" in engine audio = (ROOT / "src_graphics/audio_code.inc").read_text(encoding="ascii") assert "invoke PlaySoundA, ebx, 0, eax" in audio assert "20003h" in audio # SND_FILENAME | SND_NODEFAULT | SND_ASYNC legacy = (ROOT / "poker.asm").read_text(encoding="cp1251") recordings = set(native.values()) recordings.update(re.findall(r'open "(assets\\audio\\[^"\r\n]+\.wav)" type waveaudio', legacy)) checked = 0 for name in sorted(recordings): if name.endswith("gman-wakeup.wav") and not (ROOT / name).exists(): continue # Optional future voice-over. path = ROOT / name assert path.is_file(), f"Missing audio: {name}" command = f'open "{path}" type waveaudio alias audiotest' error = ctypes.windll.winmm.mciSendStringW(command, None, 0, None) assert error == 0, f"MCI cannot open {name}: {error}" try: error = ctypes.windll.winmm.mciSendStringW("set audiotest time format milliseconds", None, 0, None) assert error == 0 length = ctypes.create_unicode_buffer(64) error = ctypes.windll.winmm.mciSendStringW("status audiotest length", length, 64, None) assert error == 0 and int(length.value) > 0 finally: ctypes.windll.winmm.mciSendStringW("close audiotest", None, 0, None) if ctypes.windll.kernel32.GetACP() == 1251: error = ctypes.windll.winmm.mciSendStringA(command.encode("cp1251"), None, 0, None) assert error == 0, f"MCI A/CP1251 cannot open {name}: {error}" ctypes.windll.winmm.mciSendStringA(b"close audiotest", None, 0, None) checked += 1 print(f"PASS: {checked} WAV files decoded; native and legacy mappings verified.") if __name__ == "__main__": main()