EBLAN_ENGINE/tests/cutscene_engine_checks.inc
Игорь Федосеев aa64510def feat: stabilize fixed-tick simulation
Decouple gameplay from presentation and preserve signed movement fractions. Separate cinematic camera ownership with safe body handoff and transactional current-room restarts.

Resample input latches on focus regain, discard modal timing debt, and attach cinematic lighting to the view to match editor preview.

Verify editor 137/137 and ASM 288/288, cinematic traces, RGB bake and IPC framebuffer parity without changing project assets.
2026-10-31 22:31:20 +03:00

214 lines
7.9 KiB
PHP

.data
sceneFile db 'scene.dat',0
sceneInvalidOp db 'scene_badop.dat',0
sceneInvalidRef db 'scene_badref.dat',0
sceneInvalidText db 'scene_badtext.dat',0
sceneInvalidOrder db 'scene_badorder.dat',0
sceneInvalidFlags db 'scene_badflags.dat',0
sceneMissingEnd db 'scene_noend.dat',0
sceneTraceFile db 'cutscene_trace.bin',0
sceneFrameFile db 'cutscene_frame.bgra',0
sceneTrace dd 54 dup(0)
lastSoundFlags dd 0
soundCapture db 128 dup(0)
.code
AuditPlaySoundA PROC uses ebx ecx esi edi, path:DWORD, module:DWORD, flags:DWORD
mov eax, flags
mov lastSoundFlags, eax
mov esi, path
mov soundCapture, 0
test esi, esi
jz sound_mock_done
mov edi, OFFSET soundCapture
mov ecx, 127
sound_mock_copy:
lodsb
stosb
test al, al
jz sound_mock_done
loop sound_mock_copy
mov byte ptr [edi], 0
sound_mock_done:
mov eax, 1
ret
AuditPlaySoundA ENDP
RunCutsceneChecks PROC uses ebx ecx edx esi edi
invoke LoadSublevelBinary, OFFSET sceneFile, -1, -1, 0
CHECK eax, 1 ; load v4 track with Russian subtitles
CHECK cutsceneCount, 9 ; all serialized cutscene events loaded
CHECK cutsceneStringCount, 2 ; all serialized strings loaded
CHECK cutscenePending, 1 ; autoplay waits until normal player update
movzx eax, BYTE PTR [cutsceneStrings]
CHECK eax, 0CFh ; Russian text arrives as CP1251 bytes
call StartCutscene
mov esi, 0
scene_trace_tick:
call UpdateCutscene
mov edi, esi
imul edi, 24
add edi, OFFSET sceneTrace
mov eax, csCameraX
stosd
mov eax, csCameraY
stosd
mov eax, csCameraAngle
stosd
mov eax, cutsceneFade
stosd
mov eax, cutsceneSubtitle
stosd
mov eax, isCutsceneActive
stosd
cmp esi, 0
jne scene_trace_not_zero
CHECK lastSoundFlags, 00020003h ; WAV event uses asynchronous filename playback
CHECK DWORD PTR [soundCapture+14], 65697571h ; sound path is assets/sounds/quiet.wav
scene_trace_not_zero:
cmp esi, 2
jne scene_trace_not_two
CHECK csCameraX, 224 ; camera reaches exact interpolated X midpoint
CHECK csCameraY, 192 ; camera interpolates a negative Y delta
CHECK csCameraAngle, 0 ; pan wraps through zero along shortest arc
CHECK cutsceneFade, 8 ; fade reaches midpoint
CHECK cutsceneSubtitle, 0 ; wait blocks a later hide command
scene_trace_not_two:
inc esi
cmp esi, 9
jl scene_trace_tick
invoke Dump, OFFSET sceneTraceFile, OFFSET sceneTrace, 216
CHECK playerX, 288 ; movement reaches its exact target before END
CHECK playerY, 160 ; Y target retained after END
CHECK playerAngle, 4 ; angle target retained after END
CHECK isCutsceneActive, 0 ; END returns control
CHECK cutsceneFade, 0 ; END clears cinematic darkening
CHECK cutsceneSubtitle, -1 ; END clears subtitles
CHECK lastSoundFlags, 0 ; END stops audio
invoke LoadSublevelBinary, OFFSET sceneFile, -1, -1, 0
mov keyForward, 1
mov keyCutscene, 0
mov keySkipScene, 0
call UpdatePlayer
CHECK isCutsceneActive, 1 ; player update starts autoplay
CHECK playerX, 160 ; movement input does not move the player during the first scene frame
call UpdatePlayer
CHECK csCameraX, 192 ; next frame is driven only by cinematic interpolation
mov keySkipScene, 1
call UpdatePlayer
CHECK isCutsceneActive, 0 ; Tab skips and releases camera control
mov keySkipScene, 0
mov keyCutscene, 1
call UpdatePlayer
CHECK isCutsceneActive, 1 ; C can restart a finished scene
mov keyCutscene, 0
mov keyForward, 0
mov testFocus, 1
mov hEngineWnd, 1
; First regain focus with no scene command held; subsequent presses are real.
call PollInput
call ConsumeInputEdges
mov testKeys[VK_KEY_W*2], 8000h
mov testKeys[VK_KEY_TAB*2], 8000h
call PollInput
movzx eax, keyForward
CHECK eax, 1 ; polling records held movement independently of scene ownership
movzx eax, keySkipScene
CHECK eax, 1 ; skip input remains available in a scene
call StopCutscene
call PollInput
movzx eax, keyForward
CHECK eax, 1 ; normal input returns after scene stop
mov testKeys[VK_KEY_W*2], 0
mov testKeys[VK_KEY_TAB*2], 0
mov keyForward, 0
mov keySkipScene, 0
invoke LoadSublevelBinary, OFFSET sceneFile, -1, -1, 0
call StartCutscene
invoke LoadSublevelBinary, OFFSET sceneInvalidOp, -1, -1, 0
CHECK eax, 0 ; unknown cutscene opcode rejected
CHECK isCutsceneActive, 1 ; invalid track load keeps currently running scene
CHECK cutsceneCount, 9 ; invalid track load keeps original commands
invoke LoadSublevelBinary, OFFSET sceneInvalidRef, -1, -1, 0
CHECK eax, 0 ; invalid subtitle reference rejected
invoke LoadSublevelBinary, OFFSET sceneInvalidText, -1, -1, 0
CHECK eax, 0 ; unterminated string rejected
invoke LoadSublevelBinary, OFFSET sceneInvalidOrder, -1, -1, 0
CHECK eax, 0 ; unsorted commands rejected
invoke LoadSublevelBinary, OFFSET sceneInvalidFlags, -1, -1, 0
CHECK eax, 0 ; unsupported scene flags rejected
invoke LoadSublevelBinary, OFFSET sceneMissingEnd, -1, -1, 0
CHECK eax, 0 ; scene without END rejected
invoke LoadSublevelBinary, OFFSET mainPath, -1, -1, 0
CHECK isCutsceneActive, 0 ; a successful room load stops old playback
CHECK cutsceneCount, 0 ; a legacy room clears old commands
CHECK cutsceneStringCount, 0 ; a legacy room clears old string references
invoke LoadSublevelBinary, OFFSET sceneFile, -1, -1, 0
mov DWORD PTR [cutsceneEvents+3*sizeof CutsceneEvent+CutsceneEvent.paramB], 2
call StartCutscene
call UpdateCutscene
call UpdateCutscene
call UpdateCutscene
CHECK cutsceneSubtitle, -1 ; timed subtitle expires even while a WAIT blocks events
mov cutsceneSubtitle, 0
mov edi, OFFSET screenBuffer
mov ecx, SCREEN_W*SCREEN_H
mov eax, COLOR_BLUE
rep stosd
call RenderCutsceneOverlay
CHECK DWORD PTR [screenBuffer], COLOR_BLACK ; cinematic top letterbox
CHECK DWORD PTR [screenBuffer+200*SCREEN_PITCH], COLOR_BLACK ; cinematic bottom letterbox
CHECK DWORD PTR [screenBuffer+100*SCREEN_PITCH], COLOR_BLUE ; picture area remains visible
CHECK DWORD PTR [screenBuffer+159*SCREEN_PITCH], 0000007Fh ; subtitle panel is semitransparent
mov edi, OFFSET screenBuffer+160*SCREEN_PITCH
mov ecx, 28*SCREEN_W
xor ebx, ebx
scene_white_pixel:
cmp DWORD PTR [edi], COLOR_WHITE
jne scene_next_pixel
inc ebx
scene_next_pixel:
add edi, 4
loop scene_white_pixel
xor eax, eax
test ebx, ebx
setnz al
CHECK eax, 1 ; Russian subtitle glyphs are drawn
invoke Dump, OFFSET sceneFrameFile, OFFSET screenBuffer, FRAME_BUFFER_SIZE
mov edi, OFFSET screenBuffer
mov ecx, SCREEN_W*SCREEN_H
mov eax, 00123456h
rep stosd
mov cutsceneFade, 8
call ApplyCutsceneFade
CHECK DWORD PTR [screenBuffer], 00091A2Bh ; fade blends each RGB channel correctly
mov cutsceneFade, 16
call ApplyCutsceneFade
CHECK DWORD PTR [screenBuffer], 0 ; full cinematic fade produces black
call StopCutscene
; Scene transitions use the same validated room switch and fade sequencer.
invoke LoadSublevelBinary, OFFSET sceneFile, -1, -1, 0
mov cutsceneCount, 2
mov edi, OFFSET cutsceneEvents
mov ecx, 8
xor eax, eax
rep stosd
mov BYTE PTR [cutsceneEvents+CutsceneEvent.opCode], OP_CHANGE_SUBLEVEL
mov WORD PTR [cutsceneEvents+sizeof CutsceneEvent], 1
call StartCutscene
mov cutsceneFade, 16
call UpdateCutscene
CHECK isCutsceneActive, 0 ; changing sublevel stops the old scene
CHECK fadeState, 1 ; scripted transition starts its configured fade
CHECK fadeLevel, 16 ; transition preserves an existing cinematic fade without a bright flash
mov esi, 32
scene_transition_fade:
call UpdateScreenFade
dec esi
jnz scene_transition_fade
CHECK spriteCount, 1 ; scripted transition loads the destination room
CHECK cutsceneCount, 0 ; scripted transition cannot reuse old scene buffers
ret
RunCutsceneChecks ENDP