Trace shots against current map geometry instead of stale render depth. Preserve outline counters across volatile pixel calls and freeze gameplay on cinematic, transition and death ticks. Clamp packed HP before narrowing and match legacy archetype rules. Publish IDE saves atomically; failed saves block file switches and builds. Drain compiler output while hidden. Verify runtime/editor builds, 112 editor checks, 148 ASM checks and live preview parity. Record remaining stages in docs/STABILIZATION.md.
202 lines
7.6 KiB
PHP
202 lines
7.6 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 isCutsceneActive, 0
|
|
mov cutscenePending, 0
|
|
mov isPlayerDead, 0
|
|
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
|
|
ret
|
|
RunStabilityChecks ENDP
|