EBLAN_ENGINE/tests/stability_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

; Real gameplay procedures, deliberately without Render3DScene between shots.
.code
ResetCombatFixture PROC uses eax ecx edi
mov edi, OFFSET gameMap
mov ecx, MAP_SIZE
xor eax, eax
rep stosb
mov fadeState, 0
mov fadeLevel, 0
call ResetMovementFractions
mov isCutsceneActive, 0
mov cutscenePending, 0
mov isPlayerDead, 0
mov clockReset, 0
mov inputFocused, 1
call ConsumeInputEdges
mov keyRun, 0
mov isGamePaused, 0
mov gameDialogActive, 0
mov gameMode, GAME_MODE_ACTION
mov enableWeapons, 1
mov playerWeapon, WEAPON_PISTOL
mov playerHealth, 100
mov playerAmmo, 50
mov playerScore, 0
mov playerAttackCooldown, 0
mov playerFlashTimer, 0
mov playerHitFlash, 0
mov playerX, 160
mov playerY, 160
mov playerAngle, 0
mov keyForward, 0
mov keyBackward, 0
mov keyStrafeLeft, 0
mov keyStrafeRight, 0
mov keyTurnLeft, 0
mov keyTurnRight, 0
mov keyCutscene, 0
mov keySkipScene, 0
mov keyAction, 0
mov keyRestart, 0
mov keyAttack, 1
mov transitionCount, 0
mov spriteCount, 1
mov [spriteList].SpriteStruct.x, 288
mov [spriteList].SpriteStruct.y, 160
mov [spriteList].SpriteStruct.textureId, 13
mov [spriteList].SpriteStruct.scale, FIXED_ONE
mov [spriteList].SpriteStruct.flags, 0
call InitEntities
call UpdatePlayer
ret
ResetCombatFixture ENDP
RunStabilityChecks PROC
mov edi, OFFSET screenBuffer
mov ecx, FRAME_BUFFER_SIZE/4
mov eax, 00123456h
rep stosd
invoke DrawRectOutline, 68, 42, 60, 8, COLOR_WHITE
CHECK DWORD PTR [screenBuffer+42*SCREEN_PITCH+127*4], COLOR_WHITE ; white outline reaches top right
CHECK DWORD PTR [screenBuffer+49*SCREEN_PITCH+100*4], COLOR_WHITE ; white outline draws bottom edge
CHECK DWORD PTR [screenBuffer+45*SCREEN_PITCH+68*4], COLOR_WHITE ; white outline draws left edge
CHECK DWORD PTR [screenBuffer+45*SCREEN_PITCH+100*4], 00123456h ; outline keeps interior unchanged
invoke DrawRectOutline, 68, 42, 60, 8, 0
CHECK DWORD PTR [screenBuffer+49*SCREEN_PITCH+100*4], 0 ; black outline terminates and draws bottom
invoke DrawRectOutline, -2, -2, 5, 5, COLOR_GREEN
CHECK DWORD PTR [screenBuffer+2*SCREEN_PITCH], COLOR_GREEN ; outline clips offscreen coordinates
invoke DrawRectOutline, 100, 45, 0, 3, COLOR_WHITE
CHECK DWORD PTR [screenBuffer+45*SCREEN_PITCH+100*4], 00123456h ; zero width outline draws nothing
call ResetCombatFixture
mov DWORD PTR [depthBuffer+160*4], 0
call UpdateCombat
CHECK entityHealth, 65 ; hitscan works without a rendered depth buffer
CHECK playerAmmo, 49 ; one shot consumes one round
mov playerAttackCooldown, 0
mov byte ptr [gameMap+2*MAP_W+3], CELL_BRICK
mov DWORD PTR [depthBuffer+160*4], 999999
call UpdateCombat
CHECK entityHealth, 65 ; newly placed wall blocks a shot despite stale depth
mov playerAttackCooldown, 0
mov byte ptr [gameMap+2*MAP_W+3], CELL_DOOR_OPEN
call UpdateCombat
CHECK entityHealth, 30 ; newly opened door permits a shot without rendering
mov playerAttackCooldown, 0
mov byte ptr [gameMap+2*MAP_W+3], CELL_GLASS
call UpdateCombat
CHECK entityHealth, 30 ; solid glass blocks gameplay shots
call ResetCombatFixture
mov [spriteList].SpriteStruct.x, 800
mov [spriteList].SpriteStruct.y, 180
mov DWORD PTR [depthBuffer+160*4], 999999
call UpdateCombat
CHECK entityHealth, 100 ; distant target does not acquire a larger world hitbox
call ResetCombatFixture
mov [spriteList].SpriteStruct.x, 160
mov [spriteList].SpriteStruct.y, 288
mov playerAngle, ANGLE_90
mov DWORD PTR [depthBuffer+160*4], 0
call UpdateCombat
CHECK entityHealth, 65 ; cardinal turn uses current camera instead of previous frame
call ResetCombatFixture
mov playerAngle, ANGLE_180
mov [spriteList].SpriteStruct.x, 32
call UpdateCombat
CHECK entityHealth, 65 ; negative cardinal shot traverses the current map
call ResetCombatFixture
mov playerAngle, ANGLE_45
mov [spriteList].SpriteStruct.y, 288
call UpdateCombat
CHECK entityHealth, 65 ; diagonal shot reaches unobstructed target
mov playerAttackCooldown, 0
mov byte ptr [gameMap+2*MAP_W+3], CELL_BRICK
call UpdateCombat
CHECK entityHealth, 65 ; diagonal ray cannot pass through a wall corner
call ResetCombatFixture
mov spriteCount, 2
mov esi, OFFSET spriteList+sizeof SpriteStruct
mov [esi].SpriteStruct.x, 224
mov [esi].SpriteStruct.y, 160
mov [esi].SpriteStruct.textureId, 13
mov [esi].SpriteStruct.scale, FIXED_ONE
mov [esi].SpriteStruct.flags, 0
call InitEntities
call UpdateCombat
CHECK entityHealth, 100 ; hitscan does not damage farther overlapping guard
CHECK entityHealth[4], 65 ; hitscan selects nearest live guard independent of insertion order
call ResetCombatFixture
mov [spriteList].SpriteStruct.y, 180
mov [spriteList].SpriteStruct.scale, 2*FIXED_ONE
call UpdateCombat
CHECK entityHealth, 65 ; authored sprite scale affects world-space hitbox
mov playerAttackCooldown, 0
mov [spriteList].SpriteStruct.scale, 0
call UpdateCombat
CHECK entityHealth, 65 ; zero sprite scale retains legacy one-unit scale
call ResetCombatFixture
mov isCutsceneActive, 1
mov playerAttackCooldown, 4
call UpdateEntities
call UpdateCombat
CHECK [spriteList].SpriteStruct.x, 288 ; cinematic camera cannot attract guards
CHECK playerAmmo, 50 ; cinematic camera cannot fire
CHECK playerAttackCooldown, 4 ; cinematic pauses weapon timers
mov isCutsceneActive, 0
mov fadeState, 1
call UpdateEntities
call UpdateCombat
CHECK [spriteList].SpriteStruct.x, 288 ; transition freezes guards
CHECK playerAmmo, 50 ; transition blocks firing
mov fadeState, 0
mov cutscenePending, 1
call UpdateEntities
call UpdateCombat
CHECK [spriteList].SpriteStruct.x, 288 ; pending autoplay blocks gameplay before first scene tick
CHECK playerAmmo, 50 ; pending autoplay blocks firing
call ResetCombatFixture
mov isCutsceneActive, 1
mov keySkipScene, 1
call UpdatePlayer
call UpdateEntities
call UpdateCombat
CHECK isCutsceneActive, 0 ; skip stops cinematic playback
CHECK [spriteList].SpriteStruct.x, 288 ; skip tick does not resume guards midway through tick
CHECK playerAmmo, 50 ; skip tick cannot fire stale scene input
call ResetCombatFixture
invoke SwitchSublevel, OFFSET arenaPath, 2, 2, 0, 0
call UpdateCombat
CHECK playerAmmo, 50 ; instant transition cannot fire into newly loaded room
call ResetCombatFixture
mov [spriteList].SpriteStruct.x, 160
mov [spriteList].SpriteStruct.textureId, 14
call InitEntities
mov playerHealth, 50
mov isCutsceneActive, 1
call UpdateEntities
CHECK playerHealth, 50 ; cinematic camera cannot collect a medkit
CHECK [spriteList].SpriteStruct.textureId, 14 ; cinematic leaves pickup active
mov isCutsceneActive, 0
call UpdateEntities
CHECK playerHealth, 75 ; normal gameplay collects medkit
call ResetCombatFixture
mov isPlayerDead, 1
mov keyForward, 1
mov keyTurnRight, 1
call UpdatePlayer
call UpdateCombat
CHECK playerX, 160 ; death blocks movement
CHECK playerAngle, 0 ; death blocks turning
CHECK playerAmmo, 50 ; death blocks firing
mov isPlayerDead, 0
mov keyForward, 0
mov keyTurnRight, 0
call UpdatePlayer
mov [spriteList].SpriteStruct.flags, 0602FF01h
call InitEntities
CHECK entityHealth, 255 ; packed guard health preserves maximum byte
mov [spriteList].SpriteStruct.flags, 06026400h
call InitEntities
CHECK entityType, ENTITY_TYPE_PROP ; nonzero packed Prop never falls back to texture
mov [spriteList].SpriteStruct.flags, 0
call InitEntities
CHECK entityType, ENTITY_TYPE_GUARD ; zero flags keep legacy texture fallback
call RunIntegrationChecks
ret
RunStabilityChecks ENDP