Keithan
Keithan

Reputation: 33

Why isn't the word "falling" down the screen?

So this is the continuation of my typing word game. I have most it finished but changed a decent part of the code from before. I have almost everything done except for some reason the words print at the top of the screen and stay there. It's supposed to print at the top and slowly fall towards the bottom of the screen but it doesn't.

include Irvine32.inc

BUFMAX EQU 128
SCREEN_WIDTH EQU 80  ; Adjust this value to your desired console width
INITIAL_HEARTS EQU 3

.data
    Words BYTE "house", 0               ; List of words to be typed
          BYTE "water", 0 
          BYTE "foods", 0
          BYTE "apple", 0
          BYTE "cloud", 0 
          BYTE "eagle", 0
          BYTE "jades", 0
          BYTE "nacho", 0
          BYTE "vegas", 0
          BYTE "wacky", 0
          BYTE "cable", 0
          BYTE "excel", 0
          BYTE "cache", 0
          BYTE "debug", 0
          BYTE "erase", 0
          BYTE "image", 0

    msElapsed DWORD 0                    ; Milliseconds elapsed counter
    positionX BYTE 0                     
    positionY BYTE 0                     
    nextWord DWORD 0                     ; Index of the next word to display
    score DWORD 0                       
    correctKeys DWORD 0                  
    totalKeys DWORD 0                    
    correctWords DWORD 0                 
    hearts DWORD INITIAL_HEARTS          
    heartsMsg BYTE "Hearts: ", 0         
    scoreMsg BYTE "Game Over", 0         
    scoreDisplayMsg BYTE "Score: ", 0    
    accuracyDisplayMsg BYTE "Accuracy: ", 0 
    wpmDisplayMsg BYTE "WPM: ", 0        
    char BYTE ?                          ; Character input by user
    correctBuffer BYTE BUFMAX DUP (0)    ; Buffer to store correctly typed characters
    incorrectBuffer BYTE BUFMAX DUP (0)  ; Buffer to store incorrectly typed characters
    correctIndex DWORD 0                 
    incorrectIndex DWORD 0               
    incorrectFlag BYTE 0                 ; Flag to indicate if an incorrect character was typed
    wordPlaced BYTE 0                    ; Flag to indicate if the word has been placed at a random position
    startTime DWORD ?                    ; Start time for WPM calculation
    elapsedTime DWORD ?                  ; Elapsed time for WPM calculation
    debugMsg BYTE "Y: ", 0               ; Debug message prefix

.code
main PROC
    call Randomize                       ; Initialize random number generator
    call DrawBottomLine                  
    call InitializeGame                  
    call GameLoop                        ; Start the game loop
    invoke ExitProcess, 0                

main ENDP

InitializeGame PROC
    call GetTickCount                    ; Get the current system tick count
    mov startTime, eax                   ; Store the start time
    ret
InitializeGame ENDP

GameLoop PROC
gameLoopStart:
    call DisplayStats                    ; Display hearts, score, accuracy, and WPM
    call SetRandomPosition               ; Set random position for the word if needed
    call ClearPreviousWord               ; Clear the previous word
    call DrawWord                        ; Draw the word and buffers on the screen
    call DelayUpdate                     ; Delay for input and update position
    call ReadKey                         ; Read a key from the keyboard
    jz continueGameLoop                  ; If no key was pressed, continue the loop

    mov char, al                         ; Store the read character in char
    inc totalKeys                        ; Increment total keys pressed

    call ProcessKey                      ; Process the key pressed

    cmp [msElapsed], 2000                ; Compare msElapsed with 2000 (2 seconds)
    jl skipIncrementY                    ; Do not increase y if not 2000ms (2 sec)
    inc positionY                        ; Increment the Y position
    mov [msElapsed], 0                   ; Reset ms counter
    call DebugPrintPositionY             ; Print debug message
skipIncrementY:

    call CheckWordPosition               ; Check if the word has reached the bottom

continueGameLoop:
    jmp gameLoopStart                    ; Continue the game loop
GameLoop ENDP

SetRandomPosition PROC
    cmp wordPlaced, 1                    ; Check if the word has been placed
    je skipRandomPosition
    mov eax, SCREEN_WIDTH - 5            ; Subtract 5 to avoid overflow
    call RandomRange                     ; Generate random number in range 0 to (SCREEN_WIDTH - 5)
    mov positionX, al                    ; Set positionX to the random value
    mov positionY, 0                     ; Set positionY to the top of the screen
    mov wordPlaced, 1                    ; Set the wordPlaced flag
skipRandomPosition:
    ret
SetRandomPosition ENDP

ClearPreviousWord PROC
    mov dl, positionX                    
    mov dh, positionY                    
    call Gotoxy                          ; Move cursor to the specified (X, Y) position
    mov eax, black + (black * 16)        ; Set text color to black on black background
    call SetTextColor                    
    mov edx, OFFSET Words                ; Load address of Words array into EDX
    add edx, [nextWord]                  ; Add nextWord index to get the current word
    call WriteString                     ; Clear the current word
    ret
ClearPreviousWord ENDP

DrawWord PROC
    ; Print the new word in white
    mov dl, positionX                    
    mov dh, positionY                    
    call Gotoxy                          ; Move cursor to the specified (X, Y) position
    mov eax, white + (black * 16)        ; Set text color to white on black background
    call SetTextColor                    
    mov edx, OFFSET Words                ; Load address of Words array into EDX
    add edx, [nextWord]                  ; Add nextWord index to get the current word
    call WriteString                     ; Print the current word

    ; Draw the correctly typed characters in green over the original word
    mov dl, positionX                    
    mov dh, positionY                    
    call Gotoxy                          ; Move cursor to the specified (X, Y) position
    mov eax, green + (black * 16)        ; Set text color to green on black background
    call SetTextColor                    
    mov edx, OFFSET correctBuffer        ; Load address of correctBuffer into EDX
    call WriteString                     ; Print the correctBuffer string

    ; Draw the incorrectly typed characters in red over the original word
    mov dl, positionX                    ; Move positionX value to DL register
    add dl, BYTE PTR [correctIndex]      ; Move cursor position to correct place for incorrect characters
    mov dh, positionY                    ; Move positionY value to DH register
    call Gotoxy                          ; Move cursor to the specified (X, Y) position
    mov eax, red + (black * 16)          ; Set text color to red on black background
    call SetTextColor                    
    mov edx, OFFSET incorrectBuffer      ; Load address of incorrectBuffer into EDX
    call WriteString                     ; Print the incorrectBuffer string
    ret
DrawWord ENDP

DelayUpdate PROC
    mov eax, 10                          ; Delay to make words fall at a reasonable speed
    add [msElapsed], eax                 ; Increment msElapsed counter
    call Delay                           ; Delay for the specified time
    ret
DelayUpdate ENDP

ProcessKey PROC
    ; Check if an incorrect character has already been typed
    cmp incorrectFlag, 1                 ; Check if an incorrect character was typed
    je checkCorrectCharacter             ; If an incorrect character was typed, check for the correct character

    mov esi, OFFSET Words                ; Load address of Words array into ESI
    add esi, [nextWord]                  ; Add nextWord index to get the current word
    add esi, [correctIndex]              ; Add correctIndex value to ESI to point to the current character
    movzx ebx, char                      ; Move char to EBX and zero-extend it
    
    cmp [esi], bl                        ; Compare current character in Words with char
    jne incorrect                        ; If they are not equal, jump to incorrect

correct:
    mov esi, OFFSET correctBuffer        ; Load address of correctBuffer into ESI
    add esi, [correctIndex]              ; Add correctIndex value to ESI to point to the correct position
    mov [esi], bl                        ; Store the correct character in correctBuffer
    inc esi                              ; Increment ESI
    mov BYTE PTR [esi], 0                ; Null-terminate the correct buffer

    mov incorrectBuffer, 0               ; Clear incorrectBuffer on correct character
    mov incorrectFlag, 0                 ; Clear incorrect flag on correct character
    inc [correctIndex]                   ; Increment the correctIndex
    inc correctKeys                      ; Increment the number of correct keys

    call CheckWordCompletion             ; Check if the word is completed
    ret

incorrect:
    ; Store the incorrect character at the start of incorrectBuffer
    mov esi, OFFSET incorrectBuffer
    mov [esi], bl                        ; Store the incorrect character
    mov BYTE PTR [esi + 1], 0            ; Null-terminate the incorrect buffer
    mov incorrectFlag, 1                 ; Set the incorrect flag
    ret

checkCorrectCharacter:
    mov esi, OFFSET Words                ; Load address of Words array into ESI
    add esi, [nextWord]                  ; Add nextWord index to get the current word
    add esi, [correctIndex]              ; Add correctIndex value to ESI to point to the current character
    movzx ebx, char                      ; Move char to EBX and zero-extend it

    cmp [esi], bl                        ; Compare current character in Words with char
    je correct                           ; If they are equal, jump to correct

    ret
ProcessKey ENDP

CheckWordCompletion PROC
    mov esi, OFFSET Words                ; Load address of Words array into ESI
    add esi, [nextWord]                  ; Add nextWord index to get the current word
    add esi, [correctIndex]              ; Add correctIndex value to ESI to point to the current character
    cmp BYTE PTR [esi], 0                ; Compare current character with null terminator
    jne returnFromCheckCompletion        ; If not the end, return

    ; If a word is completed, reset indexes and move to the next word
    call ClearCurrentWord                ; Clear the current word from the screen
    mov [correctIndex], 0                ; Reset correctIndex
    mov [incorrectIndex], 0              ; Reset incorrectIndex
    add [nextWord], 6                    ; Move to next word (each word is 5 characters + null terminator)
    inc correctWords                     ; Increment the number of correct words
    mov wordPlaced, 0                    ; Reset wordPlaced flag
    mov incorrectFlag, 0                 ; Reset incorrectFlag

    cmp [nextWord], 96                   ; Check if all words are exhausted (16 words * 6 bytes each)
    jl returnFromCheckCompletion         ; If not, return

    ; Reset to the beginning of the array
    mov [nextWord], 0
returnFromCheckCompletion:
    ret
CheckWordCompletion ENDP

CheckWordPosition PROC
    cmp [positionY], 23                  ; Compare positionY with 23 (one line above bottom)
    jl continueCheckWordPosition         ; If positionY is less than 24, continue the game loop

    ; If the word reaches the bottom of the screen, reduce hearts
    call ReduceHearts
    mov eax, hearts                      ; Load hearts into eax
    cmp eax, 0                           ; Check if hearts are 0
    je endGame                           ; If no hearts left, end the game

    ; Reset word placement and continue
    call ResetWord
continueCheckWordPosition:
    ret
endGame:
    mov dl, 0                            ; Move cursor to the top-left corner
    mov dh, 0
    call Gotoxy
    mov eax, white + (black * 16)        ; Set text color to white on black background
    call SetTextColor
    mov edx, OFFSET scoreMsg             ; Load address of scoreMsg into EDX
    call WriteString                     ; Print the score message
    ret
CheckWordPosition ENDP

ResetWord PROC
    call ClearCurrentWord
    mov [correctIndex], 0                ; Reset correctIndex
    mov [incorrectIndex], 0              ; Reset incorrectIndex
    add [nextWord], 6                    ; Move to next word
    mov wordPlaced, 0                    ; Reset wordPlaced flag

    cmp [nextWord], 96                   ; Check if all words are exhausted
    jl returnFromResetWord               ; If not, return

    ; Reset to the beginning of the array
    mov [nextWord], 0
returnFromResetWord:
    ret
ResetWord ENDP

ReduceHearts PROC
    mov eax, hearts
    dec eax                              ; Decrease the number of hearts by 1
    mov hearts, eax
    ret
ReduceHearts ENDP

DisplayStats PROC
    ; Display Hearts
    mov dl, 0                            ; Set cursor position to top-left corner
    mov dh, 0
    call Gotoxy
    mov eax, white + (black * 16)        ; Set text color to white on black background
    call SetTextColor
    mov edx, OFFSET heartsMsg            ; Load address of heartsMsg
    call WriteString                     ; Print the "Hearts: " message
    mov eax, hearts
    call WriteDec                        ; Print the number of hearts

    ; Display Score
    mov dl, 0
    mov dh, 1
    call Gotoxy
    mov edx, OFFSET scoreDisplayMsg      ; Load address of scoreDisplayMsg
    call WriteString                     ; Print the "Score: " message
    mov eax, correctKeys
    call WriteDec                        ; Print the score

    ; Display Accuracy
    mov dl, 0                            ; Set cursor position to next line
    mov dh, 2
    call Gotoxy
    mov edx, OFFSET accuracyDisplayMsg   ; Load address of accuracyDisplayMsg
    call WriteString                     ; Print the "Accuracy: " message
    mov eax, correctKeys
    mov ebx, 100
    mul ebx                              ; Multiply correct keys by 100
    cdq
    cmp totalKeys, 0                     ; Check if totalKeys is zero to avoid division by zero
    je noKeysPressed
    idiv totalKeys                       ; Divide by total keys pressed
    call WriteDec                        ; Print the accuracy value
    mov dl, '%'                          ; Load '%' character into DL register
    call WriteChar                       ; Print '%'
    jmp skipNoKeys                       ; Skip the no keys pressed handler
noKeysPressed:
    mov eax, 0
    call WriteDec                        ; Print 0 for accuracy
    mov dl, '%'                          ; Load '%' character into DL register
    call WriteChar                       ; Print '%'
skipNoKeys:                              ; Label to skip the no keys pressed handler

    ; Display WPM
    call GetTickCount                    ; Get the current system tick count
    sub eax, startTime                   ; Calculate elapsed time
    mov elapsedTime, eax                 ; Store the elapsed time
    mov dl, 0
    mov dh, 3
    call Gotoxy
    mov edx, OFFSET wpmDisplayMsg        ; Load address of wpmDisplayMsg
    call WriteString                     ; Print the "WPM: " message
    mov eax, correctWords
    mov ebx, 60000
    mul ebx                              ; Multiply correct words by 60000 (milliseconds in a minute)
    cdq
    cmp elapsedTime, 0                   ; Check if elapsedTime is zero to avoid division by zero
    je noElapsedTime
    idiv elapsedTime                     ; Divide by elapsed time
    call WriteDec                        ; Print the WPM value
    jmp skipNoElapsed                    ; Skip the no elapsed time handler
noElapsedTime:
    mov eax, 0
    call WriteDec                        ; Print 0 for WPM
skipNoElapsed:                           ; Label to skip the no elapsed time handler

    ret
DisplayStats ENDP

DrawBottomLine PROC
    mov dl, 0
    mov dh, 24                           ; Set cursor position to the bottom line (24th row)
    call Gotoxy
    mov eax, white + (black * 16)        ; Set text color to white on black background
    call SetTextColor
    mov ecx, SCREEN_WIDTH
drawLineLoop:
    mov al, '-'                          ; Use '-' to draw the line
    call WriteChar                       ; Write the character to the screen
    loop drawLineLoop
    ret
DrawBottomLine ENDP

ClearCurrentWord PROC
    ; Clear the current word from the screen
    mov dl, positionX
    mov dh, positionY
    call Gotoxy

    ; Overwrite the word with spaces
    mov eax, black + (black * 16)        ; Set text color to black on black background
    call SetTextColor
    mov ecx, 5                           ; Each word has 5 characters
clearLoop:
    mov al, ' '                          ; Load space character into AL
    call WriteChar                       ; Write the space character to the screen
    loop clearLoop

    ; Reset buffers
    mov edi, OFFSET correctBuffer
    mov ecx, BUFMAX
    xor eax, eax
    rep stosb                            ; Clear correctBuffer

    mov edi, OFFSET incorrectBuffer
    mov ecx, BUFMAX
    rep stosb                            ; Clear incorrectBuffer

    ret
ClearCurrentWord ENDP

DebugPrintPositionY PROC
    ; Debug print for positionY
    movzx eax, positionY                 ; Zero-extend the byte to a 32-bit register
    mov edx, OFFSET debugMsg
    call WriteString
    call WriteDec
    call CrLf
    ret
DebugPrintPositionY ENDP

END main

I tried to fix the line inc positionY but it didn't really work. It would be greatly appreciated if you could help me out!

Upvotes: 0

Views: 51

Answers (1)

Nassau
Nassau

Reputation: 924

After these two lines ZF = 1 if user didn't press keys. So loop can go forever msElapsed and positionY will not be modified.

call ReadKey

jz continueGameLoop

But if You move label continueGameLoop: few lines up so the code keep tracking variables this will change positionY so the word will fall down.

GameLoop PROC
gameLoopStart:
    call DisplayStats                    ; Display hearts, score, accuracy, and WPM
    call SetRandomPosition               ; Set random position for the word if needed
    call ClearPreviousWord               ; Clear the previous word
    call DrawWord                        ; Draw the word and buffers on the screen
    call DelayUpdate                     ; Delay for input and update position
    call ReadKey                         ; Read a key from the keyboard
    jz continueGameLoop                  ; If no key was pressed, continue the loop

    mov char, al                         ; Store the read character in char
    inc totalKeys                        ; Increment total keys pressed

    call ProcessKey                      ; Process the key pressed

continueGameLoop:

    cmp [msElapsed], 2000                ; Compare msElapsed with 2000 (2 seconds)
    jl skipIncrementY                    ; Do not increase y if not 2000ms (2 sec)
    inc positionY                        ; Increment the Y position
    mov [msElapsed], 0                   ; Reset ms counter
    call DebugPrintPositionY             ; Print debug message

skipIncrementY:                              

    call CheckWordPosition               ; Check if the word has reached the bottom
    jmp gameLoopStart                    ; Continue the game loop
GameLoop ENDP

Anyway, 3 words touched bottom line, Hearts = 0 and this variable resets to full 32-bit value because CheckWordPosition proc returns to main game loop.

Upvotes: 0

Related Questions