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
; 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
|