EBLAN_ENGINE/tests/engine_regressions.asm
Игорь Федосеев 527d92411d chore: integrate main before stage 2
Preserve stage-1 stability fixes alongside v5 lighting, IPC v2, weapons and studio updates. Fix barrel AOE pointer corruption and extend modal gameplay gating.

Verify 137 editor checks, 191 ASM checks, lighting bake and preview parity. Document stage-2 scope without implementing it.
2026-10-31 22:10:07 +03:00

379 lines
13 KiB
NASM

include engine_api.inc
AuditGetAsyncKeyState PROTO :DWORD
AuditGetForegroundWindow PROTO
AuditPlaySoundA PROTO :DWORD, :DWORD, :DWORD
GetAsyncKeyState TEXTEQU <AuditGetAsyncKeyState>
GetForegroundWindow TEXTEQU <AuditGetForegroundWindow>
PlaySoundA TEXTEQU <AuditPlaySoundA>
CopyFileA PROTO :DWORD, :DWORD, :DWORD
include include/engine_defs.inc
include include/font8x8.inc
include include/engine_data.inc
include include/engine_math.inc
include include/engine_map.inc
include include/engine_textures.inc
include include/engine_input.inc
include include/engine_physics.inc
include include/engine_entity.inc
include include/engine_light.inc
include include/engine_raycaster.inc
include include/engine_render2d.inc
include include/engine_combat.inc
include include/engine_gameplay.inc
include include/engine_cutscene.inc
include startup_parser.inc
include project_paths.inc
.data
resultCount dd 0
results dd 256 dup(0)
resultPath db 'engine_results.bin',0
anglePath db 'angles.bin',0
framePath db 'frame.bgra',0
projectFramePath db 'project_frame.bgra',0
subPath db 'sublevel_02.dat',0
mainPath db 'map.dat',0
arenaPath db 'arena.dat',0
blackPath db 'black.dat',0
badPath db 'truncated.dat',0
missingPath db 'missing.dat',0
legacy1Path db 'legacy1.dat',0
legacy2Path db 'legacy2.dat',0
badNamePath db 'badname.dat',0
blockedPath db 'badspawn.dat',0
overflowPath db 'overflow.dat',0
orphanPath db 'orphan.dat',0
duplicatePath db 'duplicate.dat',0
validPack db 'assets/imported.bin',0
badPack db 'assets/badpack.bin',0
defaultPixels db 'assets/defaults.bin',0
defaultFile dd 0
defaultBytes dd 0
testKeys dw 256 dup(0)
testFocus dd 1
snapshot dd 6 dup(0)
CHECK MACRO value, expected
mov eax, value
cmp eax, expected
sete al
movzx eax, al
mov ecx, resultCount
mov [results+ecx*4], eax
inc resultCount
ENDM
.code
AuditGetAsyncKeyState PROC key:DWORD
mov ecx, key
movzx eax, WORD PTR [testKeys+ecx*2]
ret
AuditGetAsyncKeyState ENDP
AuditGetForegroundWindow PROC
mov eax, testFocus
ret
AuditGetForegroundWindow ENDP
Dump PROC uses ebx, path:DWORD, dataPtr:DWORD, dataSize:DWORD
LOCAL file:DWORD, written:DWORD
invoke CreateFileA, path, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0
mov file, eax
invoke WriteFile, file, dataPtr, dataSize, ADDR written, 0
invoke CloseHandle, file
ret
Dump ENDP
CaptureState PROC uses eax esi edi ecx
mov eax, playerX
mov snapshot, eax
mov eax, playerY
mov snapshot[4], eax
mov eax, spriteCount
mov snapshot[8], eax
mov eax, transitionCount
mov snapshot[12], eax
mov eax, DWORD PTR [gameMap]
mov snapshot[16], eax
mov eax, mapCeilingColor
mov snapshot[20], eax
ret
CaptureState ENDP
StateUnchanged PROC uses ebx
mov eax, playerX
cmp eax, snapshot
jne state_changed
mov eax, playerY
cmp eax, snapshot[4]
jne state_changed
mov eax, spriteCount
cmp eax, snapshot[8]
jne state_changed
mov eax, transitionCount
cmp eax, snapshot[12]
jne state_changed
mov eax, DWORD PTR [gameMap]
cmp eax, snapshot[16]
jne state_changed
mov eax, mapCeilingColor
cmp eax, snapshot[20]
jne state_changed
mov eax, 1
ret
state_changed:
xor eax, eax
ret
StateUnchanged ENDP
include tests/cutscene_engine_checks.inc
include tests/lighting_engine_checks.inc
include tests/stability_engine_checks.inc
include tests/integration_engine_checks.inc
AuditMain PROC
call InitMathTables
invoke Dump, OFFSET anglePath, OFFSET tableRayAngleOffset, SCREEN_W*4
call ParseStartupMap
CHECK DWORD PTR [startupMapPath], 65636170h ; quoted command-line start map (pace...)
call GenerateDefaultTextures
invoke CreateFileA, OFFSET defaultPixels, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
mov defaultFile, eax
invoke ReadFile, defaultFile, OFFSET texturePackStaging, MAX_TEXTURES*TEX_SIZE_BYTES, OFFSET defaultBytes, 0
invoke CloseHandle, defaultFile
mov esi, OFFSET texturePackStaging
mov edi, OFFSET textureBuffer
mov ecx, MAX_TEXTURES*TEX_SIZE_BYTES/4
repe cmpsd
sete al
movzx eax, al
CHECK eax, 1 ; editor fallback previews match all engine default pixels
CHECK DWORD PTR [textureBuffer+10*TEX_SIZE_BYTES], COLOR_CHROMA_KEY ; default lamp exists independently of portal
invoke CopyFileA, OFFSET validPack, OFFSET szTexPackPath, 0
mov ecx, 128
dirty_stack:
push 0A5A5A5A5h
loop dirty_stack
add esp, 512
call LoadTexturePack
CHECK eax, 1 ; valid texture pack loads with dirty stack
CHECK DWORD PTR [textureBuffer+TEX_SIZE_BYTES], 00112233h ; imported PNG reaches ASM unchanged
CHECK DWORD PTR [textureBuffer+11*TEX_SIZE_BYTES], COLOR_CHROMA_KEY ; imported sprite transparency reaches ASM
invoke CopyFileA, OFFSET badPack, OFFSET szTexPackPath, 0
call LoadTexturePack
CHECK eax, 0 ; truncated texture pack rejected
CHECK DWORD PTR [textureBuffer+TEX_SIZE_BYTES], 00112233h ; failed pack load preserves current pixels
mov startupMapPath, 0
call LoadMapBinary
CHECK eax, 1 ; startup main map loads
CHECK spriteCount, 2 ; startup sprite count
CHECK transitionCount, 1 ; startup transition count
invoke SwitchSublevel, OFFSET subPath, 4, 6, 0, 0
CHECK spriteCount, 1 ; instant transition replaces sprites
CHECK playerX, 288 ; destination X spawn
CHECK playerY, 416 ; destination Y spawn
invoke SwitchSublevel, OFFSET mainPath, 2, 2, 0, 1
mov esi, 32
fade_frames:
call ApplyScreenFade
dec esi
jnz fade_frames
CHECK fadeState, 0 ; fade finishes and releases player
CHECK fadeLevel, 0 ; fade returns full brightness
CHECK spriteCount, 2 ; fade transition loads destination
invoke LoadSublevelBinary, OFFSET arenaPath, -1, -1, 0
CHECK eax, 1 ; map basename beginning with a resolves in assets
invoke LoadSublevelBinary, OFFSET legacy1Path, -1, -1, 0
CHECK eax, 1 ; legacy v1 accepted
CHECK DWORD PTR [spriteList], 224 ; legacy sprite coordinates converted
invoke LoadSublevelBinary, OFFSET legacy2Path, -1, -1, 0
CHECK eax, 1 ; legacy extended v2 accepted
CHECK transitionCount, 1 ; legacy v2 transitions retained
invoke LoadSublevelBinary, OFFSET blackPath, -1, -1, 0
CHECK eax, 1 ; black palette map loads
CHECK mapCeilingColor, 0 ; black ceiling applied
CHECK mapFloorColor, 0 ; black floor applied
call CaptureState
invoke SwitchSublevel, OFFSET missingPath, 2, 2, 0, 0
call StateUnchanged
CHECK eax, 1 ; missing destination preserves current room
CHECK mapErrorFrames, 180 ; failed transition reports an error
invoke LoadSublevelBinary, OFFSET badPath, -1, -1, 0
CHECK eax, 0 ; truncated map rejected
call StateUnchanged
CHECK eax, 1 ; truncated load preserves current room
invoke LoadSublevelBinary, OFFSET badNamePath, -1, -1, 0
CHECK eax, 0 ; unterminated target filename rejected
invoke LoadSublevelBinary, OFFSET blockedPath, -1, -1, 0
CHECK eax, 0 ; blocked spawn rejected
invoke LoadSublevelBinary, OFFSET overflowPath, -1, -1, 0
CHECK eax, 0 ; object count overflow rejected without clamping
invoke LoadSublevelBinary, OFFSET orphanPath, -1, -1, 0
CHECK eax, 0 ; portal without transition rejected
invoke LoadSublevelBinary, OFFSET duplicatePath, -1, -1, 0
CHECK eax, 0 ; duplicate triggers rejected
invoke LoadSublevelBinary, OFFSET mainPath, 0, 0, 0
CHECK eax, 0 ; transition spawn inside a wall rejected
call StateUnchanged
CHECK eax, 1 ; invalid spawn leaves current room intact
mov esi, OFFSET missingPath
mov edi, OFFSET startupMapPath
copy_missing_startup:
lodsb
stosb
test al, al
jnz copy_missing_startup
call LoadMapBinary
CHECK DWORD PTR [gameMap], 01010101h ; missing startup map creates the procedural fallback
CHECK spriteCount, 0 ; fallback clears stale sprites
CHECK transitionCount, 0 ; fallback clears stale transitions
mov startupMapPath, 0
; Re-entering an occupied destination trigger must not bounce back.
invoke LoadSublevelBinary, OFFSET subPath, 2, 2, 0
mov mapErrorFrames, 0
call CheckPortalTriggers
CHECK spriteCount, 1 ; destination trigger is latched on spawn
mov playerX, 224
call CheckPortalTriggers
mov playerX, 160
call CheckPortalTriggers
CHECK fadeState, 1 ; leaving and re-entering a trigger activates it
mov fadeState, 0
mov fadeLevel, 0
; Input APIs are mocked; PollInput itself is the production procedure.
mov hEngineWnd, 1
mov testKeys[VK_KEY_SHIFT*2], 8000h
call PollInput
movzx eax, keyRun
CHECK eax, 1 ; Shift starts sprint
mov testKeys[VK_KEY_SHIFT*2], 0
call PollInput
movzx eax, keyRun
CHECK eax, 0 ; releasing Shift stops sprint
mov testKeys[VK_KEY_E*2], 8000h
call PollInput
movzx eax, keyAction
CHECK eax, 1 ; action emitted on first key press
call PollInput
movzx eax, keyAction
CHECK eax, 0 ; held action does not repeat
mov testKeys[VK_KEY_E*2], 0
call PollInput
mov testKeys[VK_KEY_E*2], 8000h
call PollInput
movzx eax, keyAction
CHECK eax, 1 ; releasing action re-arms it
mov testFocus, 0
call PollInput
movzx eax, keyAction
CHECK eax, 0 ; unfocused engine ignores keyboard
; Flat wall at x=640, player x=160: every perpendicular depth is 480.
mov edi, OFFSET gameMap
mov ecx, MAP_SIZE
xor eax, eax
rep stosb
xor ecx, ecx
straight_wall:
mov eax, ecx
shl eax, 5
mov byte ptr [gameMap+eax+10], CELL_BRICK
inc ecx
cmp ecx, MAP_H
jl straight_wall
mov playerX, 160
mov playerY, 1024
mov playerAngle, 0
mov spriteCount, 0
call Render3DScene
mov esi, OFFSET depthBuffer
mov ecx, SCREEN_W
mov ebx, 1
check_flat_depth:
cmp DWORD PTR [esi], 480
je flat_depth_ok
xor ebx, ebx
flat_depth_ok:
add esi, 4
loop check_flat_depth
CHECK ebx, 1 ; all 320 columns of a flat wall have exactly the same depth
invoke Dump, OFFSET framePath, OFFSET screenBuffer, FRAME_BUFFER_SIZE
; Overlapping sprites are sorted far-to-near, independent of insertion order.
mov spriteCount, 2
mov esi, OFFSET spriteList
mov [esi].SpriteStruct.x, 288
mov [esi].SpriteStruct.y, 1024
mov [esi].SpriteStruct.scale, FIXED_ONE
mov [esi].SpriteStruct.textureId, 11
add esi, sizeof SpriteStruct
mov [esi].SpriteStruct.x, 416
mov [esi].SpriteStruct.y, 1024
mov [esi].SpriteStruct.scale, FIXED_ONE
mov [esi].SpriteStruct.textureId, 12
call Render3DScene
CHECK spriteOrder, 1 ; farther sprite draws first
CHECK spriteOrder[4], 0 ; nearer sprite draws last
; Sprite slot 10 can be replaced without repainting wall portals.
mov edi, OFFSET textureBuffer+10*TEX_SIZE_BYTES
mov ecx, TEX_SIZE_BYTES/4
mov eax, COLOR_RED
rep stosd
mov edi, OFFSET portalTextureBuffer
mov ecx, TEX_SIZE_BYTES/4
mov eax, COLOR_GREEN
rep stosd
mov byte ptr [gameMap+16*MAP_W+10], CELL_PORTAL
mov spriteCount, 0
call Render3DScene
CHECK DWORD PTR [screenBuffer+120*SCREEN_PITCH+160*4], 00007F00h ; portal uses separate artwork despite imported sprite slot 10
mov byte ptr [gameMap+16*MAP_W+10], CELL_BRICK
; Scaling a sprite changes its height, not the floor point at its depth.
mov edi, OFFSET textureBuffer+11*TEX_SIZE_BYTES
mov ecx, TEX_SIZE_BYTES/4
mov eax, COLOR_RED
rep stosd
mov spriteCount, 1
mov esi, OFFSET spriteList
mov [esi].SpriteStruct.scale, 2*FIXED_ONE
call Render3DScene
CHECK DWORD PTR [screenBuffer+179*SCREEN_PITCH+160*4], COLOR_RED ; scaled sprite still reaches its floor point
mov eax, DWORD PTR [screenBuffer+180*SCREEN_PITCH+160*4]
cmp eax, COLOR_RED
setne al
movzx eax, al
CHECK eax, 1 ; scaled sprite does not sink into the floor
; Cardinal rays must not divide by zero or wrap DDA distances.
mov spriteCount, 0
mov playerAngle, ANGLE_90
call Render3DScene
CHECK DWORD PTR [depthBuffer+160*4], 1024 ; exact cardinal ray handles zero X direction
call GenerateDefaultTextures
invoke CopyFileA, OFFSET projectPackPath, OFFSET szTexPackPath, 0
call LoadTexturePack
CHECK eax, 1 ; actual project texture pack loads
invoke LoadSublevelBinary, OFFSET projectMapPath, -1, -1, 0
CHECK eax, 1 ; actual project map loads in ASM
call Render3DScene
invoke Dump, OFFSET projectFramePath, OFFSET screenBuffer, FRAME_BUFFER_SIZE
call RunLightingChecks
call RunCutsceneChecks
call RunStabilityChecks
mov eax, resultCount
inc eax
shl eax, 2
invoke Dump, OFFSET resultPath, OFFSET resultCount, eax
invoke ExitProcess, 0
AuditMain ENDP
END AuditMain