KAZIK/tools/tests/check_audio_bindings.py
Artvasil09 3ad5bf4c9d Develop assembly-only casino scenes and native games
Add native Durak, poker, blackjack, roulette, Buckshot and billiards scenes with animation assets and regression tests. Improve arrival, city, hall, profiles, shops, audio and exit handling; remove the portable C game core and refresh shipping executables.
2026-10-08 22:39:19 +03:00

72 lines
3.5 KiB
Python

"""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"]:
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"]
engine = (ROOT / "casino3d.inc").read_text(encoding="cp1251")
assert "invoke PlaySoundA, OFFSET sound" not in engine
assert "call InitSounds" in engine.split("run_game_body:")[1].split("LaunchClassicGame ENDP")[0]
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()