Group level edits across inspector and canvas gestures, preserve legacy maps, and expose opt-in switch/key door bindings without changing wire layouts. Refresh studio and pause UI with UE5-inspired surfaces and content drawer. Verify 162 editor and 307 ASM checks plus renderer parity.
385 lines
13 KiB
NASM
385 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 include/engine_simulation.inc
|
|
include startup_parser.inc
|
|
include project_paths.inc
|
|
|
|
.data
|
|
resultCount dd 0
|
|
results dd 512 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
|
|
include tests/simulation_engine_checks.inc
|
|
include tests/studio_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 UpdateScreenFade
|
|
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 ConsumeInputEdges
|
|
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
|
|
call RunSimulationChecks
|
|
call RunStudioChecks
|
|
mov eax, resultCount
|
|
inc eax
|
|
shl eax, 2
|
|
invoke Dump, OFFSET resultPath, OFFSET resultCount, eax
|
|
invoke ExitProcess, 0
|
|
AuditMain ENDP
|
|
END AuditMain
|