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.
214 lines
7.9 KiB
PHP
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
|