; ============================================================================== ; EBLAN ENGINE - Player Movement, Physics & Collision Handling ; ============================================================================== .code ; Shared gameplay gate. Returns EAX != 0 when simulation must be frozen. ; UpdatePlayer owns the per-tick latch; renderer never changes this decision. IsGameplayBlocked PROC mov eax, gameplayTickBlocked or eax, isPlayerDead or eax, isCutsceneActive or eax, cutscenePending or eax, fadeState or eax, isGamePaused or eax, gameDialogActive ret IsGameplayBlocked ENDP ; ------------------------------------------------------------------------------ ; UpdatePlayer: Updates rotation, computes movement vector & handles collisions ; ------------------------------------------------------------------------------ UpdatePlayer PROC uses ebx ecx edx esi edi LOCAL moveX:DWORD, moveY:DWORD LOCAL speed:DWORD LOCAL nextX:DWORD, nextY:DWORD LOCAL checkGridX:DWORD, checkGridY:DWORD mov gameplayTickBlocked, 1 cmp isGamePaused, 0 jne update_player_done cmp gameDialogActive, 0 jne update_player_done cmp isPlayerDead, 0 jne update_player_done ; Freeze player movement and inputs during level transitions cmp fadeState, 0 jne update_player_done cmp cutscenePending, 0 je scene_manual_start call StartCutscene scene_manual_start: cmp keyCutscene, 0 je scene_check_active cmp isCutsceneActive, 0 jne scene_check_active call StartCutscene scene_check_active: cmp isCutsceneActive, 0 je normal_player_update cmp keySkipScene, 0 je scene_update_tick call StopCutscene ret scene_update_tick: call UpdateCutscene ret normal_player_update: mov gameplayTickBlocked, 0 mov moveX, 0 mov moveY, 0 ; 1. Handle Camera Rotation cmp keyTurnLeft, 0 je check_turn_right mov eax, playerAngle sub eax, playerTurnSpeed and eax, ANGLE_MASK mov playerAngle, eax check_turn_right: cmp keyTurnRight, 0 je check_action mov eax, playerAngle add eax, playerTurnSpeed and eax, ANGLE_MASK mov playerAngle, eax check_action: cmp keyAction, 0 je check_movement call InteractDoor cmp fadeState, 0 jne update_player_done cmp gameplayTickBlocked, 0 jne update_player_done ; 2. Determine Movement Speed check_movement: mov eax, playerMoveSpeed ; Base speed: raw units/frame cmp keyRun, 0 je @F mov eax, playerRunSpeed ; Sprint speed @@: mov speed, eax ; 3. Forward / Backward Vector cmp keyForward, 0 je check_backward mov eax, playerAngle and eax, ANGLE_MASK ; dx += cos(angle) * speed mov ebx, [tableCos + eax*4] imul ebx, speed sar ebx, 16 add moveX, ebx ; dy += sin(angle) * speed mov ecx, [tableSin + eax*4] imul ecx, speed sar ecx, 16 add moveY, ecx check_backward: cmp keyBackward, 0 je check_strafe_left mov eax, playerAngle and eax, ANGLE_MASK mov ebx, [tableCos + eax*4] imul ebx, speed sar ebx, 16 sub moveX, ebx mov ecx, [tableSin + eax*4] imul ecx, speed sar ecx, 16 sub moveY, ecx ; 4. Strafe Left / Right Vector (Angle +/- 90 degrees) check_strafe_left: cmp keyStrafeLeft, 0 je check_strafe_right ; Left vector is (angle - 128) mov eax, playerAngle sub eax, ANGLE_90 and eax, ANGLE_MASK mov ebx, [tableCos + eax*4] imul ebx, speed sar ebx, 16 add moveX, ebx mov ecx, [tableSin + eax*4] imul ecx, speed sar ecx, 16 add moveY, ecx check_strafe_right: cmp keyStrafeRight, 0 je apply_physics ; Right vector is (angle + 128) mov eax, playerAngle add eax, ANGLE_90 and eax, ANGLE_MASK mov ebx, [tableCos + eax*4] imul ebx, speed sar ebx, 16 add moveX, ebx mov ecx, [tableSin + eax*4] imul ecx, speed sar ecx, 16 add moveY, ecx ; 5. Apply Movement with Wall-Sliding Collision Detection apply_physics: mov eax, moveX or eax, moveY jz update_player_done ; No movement input ; --- Test X Movement --- mov eax, playerX add eax, moveX mov nextX, eax ; Buffer check (collision body radius) mov ebx, nextX cmp moveX, 0 jge @F mov eax, playerRadius sub ebx, eax ; Moving left: check left edge jmp check_x_col @@: mov eax, playerRadius add ebx, eax ; Moving right: check right edge check_x_col: sar ebx, 6 ; divide by CELL_SIZE (64) mov checkGridX, ebx mov ecx, playerY sar ecx, 6 mov checkGridY, ecx invoke GetMapCell, checkGridX, checkGridY cmp eax, CELL_PORTAL je allow_portal_x invoke IsSolidCell, eax test eax, eax jnz skip_x_move ; Collision on X: slide along wall! allow_portal_x: mov eax, nextX mov playerX, eax skip_x_move: ; --- Test Y Movement --- mov eax, playerY add eax, moveY mov nextY, eax mov ecx, nextY cmp moveY, 0 jge @F mov eax, playerRadius sub ecx, eax jmp check_y_col @@: mov eax, playerRadius add ecx, eax check_y_col: sar ecx, 6 mov checkGridY, ecx mov ebx, playerX sar ebx, 6 mov checkGridX, ebx invoke GetMapCell, checkGridX, checkGridY cmp eax, CELL_PORTAL je allow_portal_y invoke IsSolidCell, eax test eax, eax jnz update_player_done ; Collision on Y allow_portal_y: mov eax, nextY mov playerY, eax update_player_done: call IsGameplayBlocked test eax, eax jnz @F call CheckPortalTriggers @@: ret UpdatePlayer ENDP