;########################################
;#                                      #
;#   Idan Cohen(17 Years old)           #
;#                                      #
;########################################
IDEAL
MODEL small
STACK 100h
DATASEG

; EQU --------------------------------
ZERO equ 0
; Colors -----------------------------
RED equ 180               ; Red color
LIGHT_BROWN EQU 120       ; Light brown color
; ------------------------------------
; Ascii ------------------------------
CARRIAGERET equ 13
;-------------------------------------
; Apples settings ----------------------
MANY_APPLES EQU 3
APPLES_START_Y equ 4
SPEED_MOVE equ 7
X_START_APPLE1 EQU 30
X_START_APPLE2 EQU 100
X_START_APPLE3 EQU 150
Y_START_APPLE2 EQU 64
Y_START_APPLE3 EQU 124
APPLE_SIZE EQU 10
; --------------------------------------
; Bucket setting -----------------------
X_START_BUCKET EQU 125
Y_START_BUCKET EQU 180
X_SIZE_BUCKET EQU 50
Y_SIZE_BUCKET EQU 20
; --------------------------------------
; Time ---------------------------------
SECOND EQU 18
; --------------------------------------
; Ports --------------------------------
DIVISOR EQU 42h
SPEAKERS EQU 61h
ACCESS_SPEAKERS EQU 43h
; --------------------------------------
OBJECTS_COUNT EQU 6
SCREEN_CORNER EQU 270
PRINT_NULL_COUNT EQU 613

; Variables -----------------------------------------------------------------------------------------------------------

CountApples db ZERO,ZERO,ZERO,ZERO,'$' ; Apples count

StringNull db ZERO,'$'

; Setting for photos ------------------------------------------------------------------
ErrorMsg db 'Error','$'                ; Error message
Header db 54 dup(ZERO)                 ; Header of photo
Palette db 256*4 dup(ZERO)             ; Palette of colors(256 colors(1 color = 4 bytes))
ScrLine db 320 dup(ZERO)               ; Screen line
;--------------------------------------------------------------------------------------

; Bucket -------------------
Bucket dw X_START_BUCKET,Y_START_BUCKET,X_SIZE_BUCKET,Y_SIZE_BUCKET,LIGHT_BROWN
; --------------------------

; Apples -------------------
Apple1 dw X_START_APPLE1,APPLES_START_Y,ZERO,APPLE_SIZE,RED
Apple2 dw X_START_APPLE2,Y_START_APPLE2,ZERO,APPLE_SIZE,RED
Apple3 dw X_START_APPLE3,Y_START_APPLE3,ZERO,APPLE_SIZE,RED
; --------------------------

; Photos --------------------------
WallpaperStart db 'start.bmp',ZERO                     ; Photo for start screen
WallpaperGame db 'wallgm.bmp',ZERO                     ; Photo for game screen
WallpaperEnd db 'TheEnd.bmp',ZERO                      ; Photo for end screen
WallpaperCredits db 'Credits.bmp',ZERO                 ; Photo for credits screen
WallpaperInstructions db 'Instru.bmp',ZERO             ; Photo for instructions screen
; ---------------------------------

; Array photo -------------------------------------------------------------------------------------------------------
PhotoStartArray dw offset WallpaperStart,offset ErrorMsg,offset Header,offset Palette,offset ScrLine ; Wallpaper for start screen
PhotoCreditsArray dw offset WallpaperCredits,offset ErrorMsg,offset Header,offset Palette,offset ScrLine ; Wallpaper for credits screen
PhotoGameArray dw offset WallpaperGame,offset ErrorMsg,offset Header,offset Palette,offset ScrLine ; Wallpaper for game screen
PhotoEndArray dw offset WallpaperEnd,offset ErrorMsg,offset Header,offset Palette,offset ScrLine ; Wallpaper for end screen
PhotoInstructionsArray dw offset WallpaperInstructions,offset ErrorMsg,offset Header,offset Palette,offset ScrLine ; Wallpaper for end screen
; -------------------------------------------------------------------------------------------------------------------

; Sound ---------------------------
SoundLe dw 0a98h
; ---------------------------------

ObjectsDisplay dw OBJECTS_COUNT,offset PhotoGameArray,offset Apple1,offset Apple2,offset Apple3,offset Bucket,offset CountApples

 ; --------------------------------------------------------------------------------------------------------------------
CODESEG

;########################################
;#                                      #
;#   Params: Nothing                    #
;#                                      #
;#   GraphicMode - change the mode to   #
;#   graphic mode                       #
;#                                      #
;########################################
proc GraphicMode
    push ax             ; Backup
    mov ax, 13h         ; Graphic mode
    int 10h
    pop ax              ; Restore
    ret
endp GraphicMode


;########################################
;#                                      #
;#   Params: Values of X, Y and Color   #
;#                                      #
;#   PutPixel - Insert pixel to screen  #
;#                                      #
;########################################
proc PutPixel               ; by value
    push bp                 ; Backup
    mov bp, sp
    push cx
    push dx
    push ax                 ; Finish backup
    mov cx,[bp+8]           ; x
    mov dx,[bp+6]           ; y
    mov al,[bp+4]           ; color
    mov ah,0Ch              ; Put pixel
    int 10h
    pop ax                  ; Restore
    pop dx
    pop cx
    pop bp                  ; Finish restore
    ret 6
endp PutPixel


;########################################
;#                                      #
;#   Params: Values of X, Y, Count,     #
;#   Color                              #
;#                                      #
;#   Vline - Draws a vertical line      #
;#                                      #
;#                                      #
;########################################
proc VLine                  ; by value
    push bp                 ; Backup
    mov bp, sp
    push ax
    push bx
    push cx
    push dx                 ; Finish backup
    mov ax, [bp+10]         ; x start
    mov bx, [bp+8]          ; y start
    mov cx, [bp+6]          ; count
    mov dx, [bp+4]          ; color
    VerticalDrawing:
        push ax             ; Push x
        push bx             ; Push y
        push dx             ; Push color
        call PutPixel
        inc ax              ; Add 1 to ax(x)
    loop VerticalDrawing
    pop dx                  ; Restore
    pop cx
    pop bx
    pop ax
    pop bp                  ; Finish restore
    ret 8
endp VLine
    

;############################################
;#                                          #
;#   Params: Array of rect				    #
;#   						                #
;#                                          #
;#   Print_rect - Draws a rectangle         #
;#                                          #
;#                                          #
;############################################
proc Print_rect             ; by value
    push bp                 ; Backup
    mov bp, sp
    push ax
    push bx
    push cx
    push dx
    push si 	
	push di					; Finish backup
    mov si, [bp+4]
    mov ax, [si]          	; x start
    mov bx, [si+2]          ; y start
    mov dx, [si+4]          ; x size
    cmp dx, ZERO
    je Print_rectExit       ; If dx(x size) == 0, jump to Print_rectExit
    mov cx, [si+6]          ; y size
    cmp cx, ZERO
    je Print_rectExit       ; If cx(y size) == 0, jump to Print_rectExit
    mov di, [si+8]          ; color
    InflationDrawing:
        push ax             ; x start
        push bx             ; y start
        push dx             ; count
        push di             ; color
        call VLine
        inc bx              ; Add 1 to bx
    loop InflationDrawing
    Print_rectExit:
	pop di					; Restore
    pop si                  
    pop dx
    pop cx
    pop bx
    pop ax
    pop bp                  ; Finish Restore
    ret 2
endp Print_rect


;############################################
;#                                          #
;#   Params: Array of rect				    #
;#   						                #
;#                                          #
;#   MoveObjectDown - Move the rect down    #
;#                                          #
;#                                          #
;############################################
proc MoveObjectDown ; offset of rect
    push bp                     ; Backup
    mov bp, sp
	push ax
	push bx
    mov bx, [bp+4]              ; offset of rect
    mov ax, [bx+2]              ; y start
    add ax, SPEED_MOVE           ; y start + 7
    mov [bx+2], ax              ; Save y start               
	pop bx                      ; Restore
	pop ax
    pop bp                      ; Finish restore
	ret 2 
endp MoveObjectDown


;####################################################################################################
;#                                                                                                  #
;#   Params: {Count of array > offset of array wallpaper > {offset of Rects} > offset of text }(dw) #
;#   						                                                                        #
;#                                                                                                  #
;#   UpdateDisplay - Update display of game                                                         #
;#                                                                                                  #
;#                                                                                                  #
;####################################################################################################
proc UpdateDisplay              ;  {Count of array > offset of array wallpaper > {offset of Rects} > offset of text }(dw)
    push bp                     ; Backup
    mov bp, sp
    push bx
    push cx                     ; Backup
    mov bx, [bp+4]              ; Offset of array of offset
    mov cx, [bx]                ; Count of objects in array
    add bx, 2                   ; bx += 2
    push [bx]                   ; push the offset of wallpaper
    call PrintPhotoByArray      ; Print Photo
    add bx, 2                   ; bx += 2
    sub cx, 2                   ; cx -= 2
    UpdateDisplayPrintRects:    ; Loop for print rects
        push [bx]               ; push offset of array rect
        call Print_rect         ; print rect
        add bx, 2               ; bx += 2
    loop UpdateDisplayPrintRects
    push [bx]                   ; push offset of text
    call PrintNewString            ; print text
    pop cx                      ; Restore
    pop bx
    pop bp                      ; Finish restore
    ret 4
endp UpdateDisplay

;############################################
;#                                          #
;#   Params: Offset of filename, offset 	#
;#   of Error message						#
;#                                          #
;#   OpenFile - open file                   #
;#                                          #
;#                                          #
;#   Return - filehandle                    #
;#                                          #
;#                                          #
;############################################
proc OpenFile                   ; offset Filename(ref) > offset Error message(ref)
    push bp                     ; Backup
    mov bp, sp
    push ax
    push dx                     ; Finish backup
    mov ah, 3dh                 ; open file(for int)
    xor al, al
    mov dx, [bp+6]              ; offset of filename
    int 21h
    jc openerror                ; if Carry flag = 1, jmp openerror
    mov [bp+6], ax              ; file handle
    jmp ExitOpenFile
    openerror:
        mov dx, [bp+4]          ; offset ErrorMsg
        mov ah, 9h              ; print string
        int 21h
    ExitOpenFile:
        pop dx                  ; Restore
        pop ax
        pop bp                  ; Finish restore
    ret 2                       ; Return file handle to bp+4
endp OpenFile

;############################################
;#                                          #
;#   Params: Offset of header(54 Bytes),	#
;#   filehandle				                #
;#                                          #
;#   ReadHeader - Read BMP file header      #
;#                                          #
;############################################
proc ReadHeader ; offset header(54 Bytes) > filehandle
                                ; Read BMP file header, 54 bytes
    push bp                     ; Backup
    mov bp, sp
    push ax
    push bx
    push cx
    push dx                     ; Finish backup
    mov ah, 3fh                 ; Read from file
    mov bx, [bp+4]              ; filehandle
    mov cx, 54                  ; size of header(bytes)
    mov dx, [bp+6]              ; offset header
    int 21h
    pop dx                      ; Restore
    pop cx
    pop bx
    pop ax
    pop bp                      ; Finish restore
    ret 4
endp ReadHeader

;############################################
;#                                          #
;#   Params: Offset of palette          	#
;#   						                #
;#                                          #
;#   ReadPalette - Read color to palette    #
;#                                          #
;############################################
proc ReadPalette ; offset of palette
    push bp                     ; Backup
    mov bp, sp
    push ax
    push bx
    push cx
    push dx                     ; Finish backup
    mov ah, 3fh                 ; Read from file
    mov cx, 400h                ; 256 colors * 4 bytes = 400h
    mov dx, [bp+4]              ; offset of palette
    int 21h
    pop dx                      ; Restore
    pop cx
    pop bx
    pop ax
    pop bp                      ; Finish restore
    ret 2
endp ReadPalette

;############################################
;#                                          #
;#   Params: Offset of palette          	#
;#   						                #
;#                                          #
;#   CopyPal - copy the color from palette  #
;#   oppiste                                #
;#                                          #
;#                                          #
;############################################
proc CopyPal ; Offset of palette
    push bp                    ; Backup
    mov bp,sp
    push ax
    push cx
    push dx
    push si                     ; Finish backup
    mov si, [bp+4]              ; offset of palette
    mov cx, 256                 ; many color
    mov dx, 3c8h                ; starting port
    xor al, al
    out dx, al                  ; copy starting color to port 3C8h
    inc dx
    PalLoop:
        mov al, [si+2]          ; Get red value
        shr al, 2               ; Max is 255, but video palette maximal
                                ; Value is 63. Therefore dividing by 4
        out dx, al
        mov al, [si+1]          ; Get green value
        shr al, 2
        out dx, al              ; Sent it
        mov al, [si]            ; Get blue value
        shr al, 2
        out dx, al              ; Sent it
        add si, 4               ; Point to next color
                                ; (There is null chr. after every color)
    loop PalLoop
    pop si                      ; Restore
    pop dx
    pop cx
    pop ax
    pop bp                      ; Finish restore
    ret 2
endp CopyPal

;############################################
;#                                          #
;#   Params: Offset of Scrline          	#
;#   						                #
;#                                          #
;#   CopyBitmap - copy the color to screen  #
;#                                          #
;#                                          #
;############################################
proc CopyBitmap ; offset ScrLine
    push bp                     ; Backup
    mov bp, sp
    push ax
    push cx
    push dx
    push es
    push di
    push si                     ; Finish backup
    mov ax, 0A000h              ; address of video card
    mov es, ax
    mov cx, 200                 ; Height = 200px
    PrintBMPLoop:
        push cx
                                ; di = cx*320, point to he correct screen line
        mov di, cx
        shl cx, 6
        shl di, 8
        add di, cx
                                ; Read one line
        mov ah, 3fh
        mov cx, 320
        mov dx, [bp+4]          ; offset Scrline
        int 21h
                                ; Copy one line into video memory
        cld                     ; Clear direction flag for movsb
        mov cx, 320
        mov si, [bp+4]          ; offset Scrline
        rep movsb               ; (move string byte) Update SI(si+1) and DI(di+1) until cx = 0
        pop cx
    loop PrintBMPLoop
    pop si                      ; Restore
    pop di
    pop es
    pop dx
    pop cx
    pop ax
    pop bp                      ; Finish restore
    ret 2
endp CopyBitmap

;############################################
;#                                          #
;#   Params: File handle                  	#
;#   						                #
;#                                          #
;#   CloseFile - Close file                 #
;#                                          #
;#                                          #
;############################################
proc CloseFile ; File handle
    push bp                     ; Backup
    mov bp, sp
    push ax
    push bx                     ; Finish backup
    mov bx, [bp+4]              ; file handle
    mov ah, 3eh                 ; Close file
    int 21h
    pop bx                      ; Restore
    pop ax
    pop bp                      ;Finish restore
    ret 2
endp CloseFile

;########################################################################################
;#                                                                                      #
;#   Params: Offset of photo(filename), offset of error message, offset of headr,       #
;#   offset of palette, offset of ScrLine                                            	#
;#   						                                                            #
;#                                                                                      #
;#   PrintPhoto - Print photo on screen                                                 #                                                                            #
;#                                                                                      #
;#                                                                                      #
;########################################################################################
proc PrintPhoto ; offset of photo > offset of error message > offset of header > offset of palette > offset of Scrline
    push bp                     ; Backup
    mov bp, sp
    push bx                     ; Finish backup
    push [bp+12]                ; offset of photo
    push [bp+10]                ; offset of error message
    call OpenFile
    pop bx                      ; return file handle
    push [bp+8]                 ; offset of header
    push bx                     ; push file handle
    call ReadHeader
    push [bp+6]                 ; offset of palette
    call ReadPalette
    push [bp+6]                 ; offset of palette
    call CopyPal
    push [bp+4]                 ; offset of Scrline
    call CopyBitmap
    push bx                     ; Push file handle
    call CloseFile              ; Close file
    pop bx                      ; Restore
    pop bp                      ; Finish restore
    ret 10
endp PrintPhoto

;############################################
;#                                          #
;#   Params: Offset of string             	#
;#   						                #
;#                                          #
;#   PrintNewString - print string          #
;#                                          #
;#                                          #
;############################################
proc PrintNewString ; Offset of string
    push bp                     ; Backup
    mov bp, sp
    push ax
    push dx                     ; Finish backup
    mov dl, CARRIAGERET
    mov ah, 2                   ; Print char
    int 21h
    push [bp+4]
    call PrintString
    pop dx                      ; Restore
    pop ax
    pop bp                      ; Finish restore
    ret 2
endp PrintNewString

;############################################
;#                                          #
;#   Params: Offset of string             	#
;#   						                #
;#                                          #
;#   PrintString - print string             #
;#                                          #
;#                                          #
;############################################
proc PrintString ; Offset of string
    push bp                     ; Backup
    mov bp, sp
    push ax
    push dx                     ; Finish backup
    mov dx, [bp+4]              ; offset of string
    mov ah, 9                   ; Print string
    int 21h
    pop dx                      ; Restore
    pop ax
    pop bp                      ; Finish restore
    ret 2
endp PrintString

;############################################
;#                                          #
;#   Params: num(val), mod(val)            	#
;#   						                #
;#   MathMod - Return mod(num % mod)        #
;#                                          #
;############################################
proc MathMod ; Num(val) > mod(val)
    push bp                     ; Backup
    mov bp, sp
    push ax
    push bx
    push dx                     ; Finish backup
    mov ax, [bp+6]              ; Num
    mov bx, [bp+4]              ; Mod
    div bx                      ; Num / Mod
    mov [bp+6], dx              ; Save
    pop dx                      ; Restore
    pop bx
    pop ax
    pop bp                      ; Finish restore
    ret 2
endp MathMod                    ; Resturn Mod

;####################################################################
;#                                          		                #
;#   Params: Num(val)(Minimum), Num(val)(65535(FFFF) Maximun)   	#
;#                      					                        #
;#                                         		                    #
;#   Random - Random until 65535(FFFF)     	   	                    #
;#                                        		                    #
;#   Return - Random num                                     	    #
;#                                        	                        #
;####################################################################
proc Random ; Num(val)(minimum) > Num(val)(65535(FFFF) maximum)
    push bp                     ; Backup
    mov bp, sp
    push ax
    push bx
    push cx 
    push dx                     ; Finish backup
    RandomStart:                ; Random start
    mov cx, 4                   ; Move to cx 4 for loop
    RandomPushZero:             ; pust to stack zero(0)
        push ZERO               ; ZERO = 0
    loop RandomPushZero
    call GetFullSystemTime      ; Return time of system
    pop ax                      ; pop hundredth(1/100)
    mov cx, 3                   ; Move to cx 3 for loop
    RandomMul:                  ; Get out params and mul with ax
        pop bx                  ; pop param
        cmp bx, ZERO
        je RandomNotMul
        mul bx                  ; mul with ax
        jmp RandomMulContinue
        RandomNotMul:
        mov bx, 23
        mul bx
        RandomMulContinue:
    loop RandomMul
    cmp ax, [bp+4]
    jb RandomStart              ; If ax > maximum, jump to RandomStart
    push ax                     ; push ax for mod
    push [bp+4]                 ; push maximun for mod
    call MathMod                ; Return mod
    pop ax                      ; mod
    cmp ax, [bp+6]
    ja ExitRandom               ; If ax > minimum, jump to ExitRandom
    jmp RandomStart
    ExitRandom:
    mov [bp+6], ax              ; Save
        pop dx                  ; Restore
        pop cx
        pop bx
        pop ax
        pop bp                  ; Finish retore
    ret 2
endp Random                     ; Return random

;####################################################
;#                                          		#
;#   Params: 4x(push 0)     						#
;#   										        #
;#                                         		    #
;#   GetFullSystemTime - Return system time		    #
;#                                        		    #
;#   Return - Hour, Minute, Second, Hundredth       #
;#                                        	        #
;####################################################
proc GetFullSystemTime ; Hour(=0) > Minute(=0) > Second(=0) > Hundredth(=0)
	push bp 					; Backup
	mov bp ,sp
	push ax
	push cx
	push dx 					; Finish Backup
	mov ah, 2ch 				; Get system time
	int 21h
	mov [bp+10], ch 			; Save hour
	mov [bp+8], cl 				; Save minute
	mov [bp+6], dh 				; Save second
	mov [bp+4], dl 				; Save hundredth
	pop dx 						; Restore
	pop cx
	pop ax
	pop bp 						; Finish restore
	ret
endp GetFullSystemTime ; Return Hour, Minute, Second, Hundredth(1/100)

;####################################################
;#                                          		#
;#   Params: Num in ascii(val)						#
;#   										        #
;#                                         		    #
;#   AsciiToDigit - Ascii to digit		   	   	    #
;#                                        		    #
;#                                        	        #
;####################################################
proc AsciiToDigit               ; Num in Ascii(val)
    push bp                     ; Backup
    mov bp, sp
    push ax                     ; Finish backup
    mov ax, [bp+4]              ; Num
    sub ax, 30h                 ; Num - 30
    mov [bp+4], ax              ; save num
    pop ax                      ; Restore
    pop bp                      ; Finish restore
    ret
endp AsciiToDigit               ; Return Digit

;####################################################
;#                                          		#
;#   Params: Num(val)								#
;#   										        #
;#                                         		    #
;#   DigitToAscii - digit to ascii		   	   	    #
;#                                        		    #
;#                                        	        #
;####################################################
proc DigitToAscii               ; Digit(val)
    push bp                     ; Backup
    mov bp, sp
    push ax                     ; Finish backup
    mov ax, [bp+4]              ; Num
    add ax, 30h                 ; Num + 30
    mov [bp+4], ax              ; save num
    pop ax                      ; Restore
    pop bp                      ; Finish restore
    ret
endp DigitToAscii               ; Return digit in ascii

;####################################################
;#                                          		#
;#   Params: Offset of string(db)(start with ascii	#
;#   of num)										#
;#                                         		    #
;#   AsciiToNum - Ascii to num		   	    	    #
;#                                        		    #
;#                                        	        #
;####################################################
proc AsciiToNum ; Offset of string(db)
    push bp                     ; Backup
    mov bp, sp
    push ax
    push bx                     ; Finish backup
    xor ax, ax                  ; reset ax
    mov bx, [bp+4]              ; move the offset of string to bx
    DaughterAsciiToNum:
        mov al, [byte ptr bx]   ; move the value in bx as byte(8 bits) to al
        cmp al, 30h
        jl ExitAsciiToNum       ; if value(in al) < 30h, so jump to ExitAsciiToNum
        cmp al, 39h
        jg ExitAsciiToNum       ; if value(in al) > 39h, so jump to ExitAsciiToNum
        push ax
        call AsciiToDigit
        pop ax                  ; Get num
        mov [byte ptr bx], al   ; Save
        inc bx                  ; bx++
        jmp DaughterAsciiToNum  ; Again
    ExitAsciiToNum:
        pop bx                  ; Restore
        pop ax
        pop bp                  ; Finish restore
    ret 2
endp AsciiToNum

;####################################################
;#                                          		#
;#   Params: Offset of string(db)(start with num)	#
;#                                         		    #
;#                                         		    #
;#   NumToAscii - Num to ascii		   	    	    #
;#                                        		    #
;#                                        	        #
;####################################################
proc NumToAscii ; Offset of string(db)
    push bp                     ; Backup
    mov bp, sp
    push ax
    push bx                     ; Finish backup
    xor ax, ax                  ; reset ax
    mov bx, [bp+4]              ; move the offset of string to bx
    DaughterNumToAscii:
        mov al, [byte ptr bx]   ; move the value in bx as byte(8 bits) to al
        cmp al, 0
        jl ExitNumToAscii       ; if value(in al) < 0, so jump to ExitAsciiToNum
        cmp al, 9
        jg ExitNumToAscii       ; if value(in al) > 9, so jump to ExitAsciiToNum
        push ax
        call DigitToAscii
        pop ax                  ; Get num
        mov [byte ptr bx], al   ; Save
        inc bx                  ; bx++
        jmp DaughterNumToAscii  ; Again
    ExitNumToAscii:
        pop bx                  ; Restore
        pop ax
        pop bp                  ; Finish restore
    ret 2
endp NumToAscii

;####################################################
;#                                          		#
;#   Params: Offset of photo array(dw)          	#
;#                                         		    #
;#                                         		    #
;#   PrintPhotoByArray - Print photo   	    	    #
;#                                        		    #
;#                                        	        #
;####################################################
proc PrintPhotoByArray ; Offset of photo array(dw)
; {offset of filename > offset of ErrorMsg > offset of Header > offset of Palette > offset of ScrLine }
	push bp 					; Backup
	mov bp, sp
	push bx 					; Finish backup
	mov bx, [bp+4] 				; photo array
	push [bx] 					; filename
	push [bx+2] 				; Error message
	push [bx+4] 				; Header
	push [bx+6] 				; Palette
	push [bx+8] 				; ScrLine
	call PrintPhoto
	pop bx 						; Restore
	pop bp 						; Finish restore
	ret 2
endp PrintPhotoByArray

;####################################################
;#                                          		#
;#   Params: x(=0) > y(=0) for return             	#
;#                                         		    #
;#                                         		    #
;#   GetLocationMouse - Get location of mouse       #
;#                                        		    #
;#                                        	        #
;####################################################
proc GetLocationMouse ; x(=0) > y(=0) for return
    push bp                     ; Backup
    mov bp, sp
    push ax
    push bx
    push cx
    push dx                     ; Finish backup
    mov ax, 3                   ; for interrup
    int 33h
    mov [bp+6], cx              ; x of location
    mov [bp+4], dx              ; y of location
    pop dx                      ; Restore
    pop cx
    pop bx
    pop ax
    pop bp                      ; Finish restore
    ret
endp GetLocationMouse           ; Return x(dw), y(dw)

;####################################################
;#                                          		#
;#   Params: Nothing                             	#
;#                                         		    #
;#                                         		    #
;#   HideMouse - Hide mouse                         #
;#                                        		    #
;#                                        	        #
;####################################################
proc ResetMouse
    push ax                     ; Backup
    mov ax, 0                   ; for interupt
    int 33h
    pop ax                      ; Restore
endp ResetMouse

;####################################################
;#                                          		#
;#   Params: param(=0) for return                  	#
;#                                         		    #
;#                                         		    #
;#   GetSystemTime - Get time of system(clock)      #
;#                                        		    #
;#                                        	        #
;####################################################
proc GetSystemTime ; param(=0) for return
    push bp                     ; Backup
    mov bp, sp
    push ax
    push es                     ; Finish backup
    mov ax, 40h                 ; port
    mov es, ax
    mov ax,[es:6ch]             ; clock
    mov [bp+4], ax
    pop es                      ; Restore
    pop ax
    pop bp                      ; Finish restore
    ret
endp GetSystemTime              ; Return time

;####################################################
;#                                          		#
;#   Params: Seconds / 0.055(dw)(Unsigned)        	#
;#                                         		    #
;#                                         		    #
;#   Delay - Delay(waiting)                         #
;#                                        		    #
;#                                        	        #
;####################################################
proc Delay ; Seconds / 0.055(dw)(Unsigned)
    push bp                     ; Backup
    mov bp, sp
    push ax
    push cx
    push dx                     ; Finish backup
    mov ax, [bp+4]              ; Seconds
    push 0                      ; for proc
    call GetSystemTime
    pop cx                      ; First time
    push 0                      ; for proc
    call GetSystemTime
    pop dx                      ; Second time
    push cx                     ; Backup first time
    sub dx, cx                  ; Second time - first time
    DelayCheck:
        cmp dx, ax              ; 10 sec (0.055 sec * 182 = 10 sec)
        ja ExitDelay            ; if dx > ax, jamp to ExitDelay
        push 0                  ; for proc
        call GetSystemTime
        pop dx                  ; Update second time
        pop cx                  ; Restore first time
        push cx                 ; Backup first time
        sub dx, cx              ; Second time - first time
    jmp DelayCheck
    ExitDelay:
        pop cx
        pop dx                  ; Restore
        pop cx
        pop ax
        pop bp                  ; Finish
    ret 2
endp Delay

;####################################################
;#                                          		#
;#   Params: Offset of string                   	#
;#                                         		    #
;#                                         		    #
;#   StringLenght - return lenght of string         #
;#                                        		    #
;#                                        	        #
;####################################################
proc StringLenght ; offset of string(db)
    push bp                             ; Backup
    mov bp, sp
    push bx                             ; Finish backup
    mov bx, [bp+4]                      ; Offset of string
    StringLenghtUntilDollar:
        cmp [byte ptr bx], '$'
        je StringLenghtExit             ; If [byte ptr bx](char) == dollar, jump to StringLenghtExit
        inc bx                          ; bx++
        jmp StringLenghtUntilDollar
    StringLenghtExit:
        sub bx, [bp+4]                  ; bx - offset of sting = count
        mov [bp+4], bx                  ; Save count
        pop bx                          ; Restore
        pop bp                          ; Finish restore
    ret
endp StringLenght                       ; Return count

;####################################################
;#                                          		#
;#   Params: Offset of string                   	#
;#                                         		    #
;#                                         		    #
;#   AppendCount - Append to count string, 1        #
;#                                        		    #
;#                                        	        #
;####################################################
proc AppendCount ; offset of string(db)
    push bp                             ; Backup
    mov bp, sp
    push bx
    push cx                             ; Finish backup
    mov bx, [bp+4]                      ; offset of string in bx
    push [bp+4]                         ; push offset of string
    call StringLenght                   ; return lenght of string
    pop cx                              ; lenght of string
    dec cx                              ; cx--
    add bx, cx                          ; bx += cx
    inc [byte ptr bx]                   ; [byte ptr bx]++
    AppendCountCheck:
        cmp [byte ptr bx], 0Ah
        jne AppendCountExit             ; If [byte ptr bx] != 0Ah, jump to AppendCount Exit
    AppendCountResetA:
        mov [byte ptr bx], 0            ; Reset [byte ptr bx]([byte ptr bx] = 0)
        cmp bx, [bp+4]
        je AppendCountExit              ; If bx == [bp+4](offset of string), jump to AppendCountExit
        inc [byte ptr bx-1]             ; [byte ptr bx-1]++
        dec bx                          ; bx--
        jmp AppendCountCheck             ; If bx > [bp+4](offset of string), jump to AppendCountCheck
    AppendCountExit:
        pop cx                          ; Restore
        pop bx
        pop bp                          ; Finish restore
    ret 2
endp AppendCount

;####################################################
;#                                          		#
;#   Params: Val(=0)                               	#
;#                                         		    #
;#                                         		    #
;#   InputKey - Get key from keyboard               #
;#                                        		    #
;#   Return - Code ascii of key                     #
;#                                        	        #
;####################################################
proc InputKey ; Val(=0)
    push bp                             ; Backup
    mov bp, sp
    push ax                             ; Finish backup
    mov ah, 7                           ; Input key
    int 21h
    mov [byte ptr bp+4], al             ; Save the key in val
    pop ax                              ; Restore
    pop bp                              ; Finish restore
    ret
endp InputKey ; Return code ascii of key

;####################################################
;#                                          		#
;#   Params: Nothing                               	#
;#                                         		    #
;#                                         		    #
;#   EnableSpeaker - Enable speakers for use        #
;#                                        		    #
;#                                        	        #
;####################################################
proc EnableSpeaker
    push ax                             ; Backup
    in al, SPEAKERS                     ; Get info form port of speakers
    or al, 00000011b                    ; Enable speakers
    out SPEAKERS, al                    ; Enter to port of speakers
    pop ax                              ; Restore
    ret
endp EnableSpeaker

;####################################################
;#                                          		#
;#   Params: Nothing                               	#
;#                                         		    #
;#                                         		    #
;#   DisableSpeaker - Disable speakers              #
;#                                        		    #
;#                                        	        #
;####################################################
proc DisableSpeaker
    push ax                             ; Backup
    in al, SPEAKERS                     ; Get info form port of speakers
    and al, 11111100b                   ; Disable speakers
    out SPEAKERS, al                    ; Enter to port of speakers
    pop ax                              ; Restore
    ret
endp DisableSpeaker

;####################################################
;#                                          		#
;#   Params: Nothing                               	#
;#                                         		    #
;#                                         		    #
;#   OpenAccessToSpeaker - Open access to speakers  #
;#                                        		    #
;#                                        	        #
;####################################################
proc OpenAccessToSpeaker
    push ax                             ; Backup
    mov al, 0b6h                        ; Move this value to al
    out ACCESS_SPEAKERS, al             ; Move the value to port because access to speakers
    pop ax                              ; Restore
    ret
endp OpenAccessToSpeaker

;####################################################
;#                                          		#
;#   Params: Byte of sound                         	#
;#                                         		    #
;#                                         		    #
;#   PlaySound - play the byte of sound             #
;#                                        		    #
;#                                        	        #
;####################################################
proc PlaySound ; Byte of sound
    push bp                             ; Backup
    mov bp ,sp
    push ax                             ; Finish backup
    mov ax, [bp+4]                      ; Byte of sound
    out DIVISOR, al                     ; Sending lower byte
    mov al, ah
    out DIVISOR, al                     ; Sending upper byte
    pop ax                              ; Restore
    pop bp                              ; Finish restore
    ret 2
endp PlaySound

;####################################################
;#                                          		#
;#   Params: Byte of sound                         	#
;#                                         		    #
;#                                         		    #
;#   Sound - play byte of sound                     #
;#                                        		    #
;#                                        	        #
;####################################################
proc Sound ; num(hz)(dw)
    push bp                             ; Backup
    mov bp, sp
    call EnableSpeaker
    call OpenAccessToSpeaker
    push [bp+4]                         ; Num(Hz)(dw)
    call PlaySound
    pop bp                              ; Restore
    ret 2
endp Sound

; ############################################## Main ##############################################
start:
    mov ax, @data
    mov ds, ax

    call GraphicMode
	HomeScreen:                                     ; Home Screen
		push offset PhotoStartArray                 ; Push offset of home screen photo
		call PrintPhotoByArray                      ; Print home screen photo
        HomeScreenInputKey:
		push ZERO                                   ; Push 0
		call InputKey                               ; Wait for key from keyboard
		pop ax                                      ; pop key to ax
		cmp ax, 'p'
		je GameScreen                               ; if key == p, jump to GameScreen
        cmp ax, 'i'
        je InstructionsScreen                       ; if ax == 'i'. jump to InstructionsScreen
		cmp ax, 'c'
		je CreditsScreen                            ; if key == c, jump to CreditsScreen
		cmp ax, 'e'
		jne HomeScreenInputKey                      ; if key != e, jump to HomeScreenInputKey
		jmp exit                                    ; jump to exit
    InstructionsScreen:
        push offset PhotoInstructionsArray          ; push offset of instructions screen photo
        call PrintPhotoByArray                      ; Print instructions screen photo
        InstructionsScreenInputKey:
        push ZERO
        call InputKey                               ; wait for  input key
        pop ax                                      ; key
        cmp ax, 'b'
        jne InstructionsScreenInputKey              ; if ax(key) != 'b', jump to InstructionsScreenInputKey
        jmp HomeScreen
	CreditsScreen:                                  ; Credits screen
		push offset PhotoCreditsArray               ; push offset of credits screen photo
		call PrintPhotoByArray                      ; Print credits screen
        CreditsScreenInputKey:
		push ZERO                                   ; push 0
		call InputKey                               ; Wait for key from keyboard
		pop ax                                      ; pop key
		cmp ax, 'b'
		jne CreditsScreenInputKey                   ; if key != b, jump to CreditsScreenInputKey
		jmp HomeScreen                              ; jump to HomeScreen
	GameScreen:                                     ; Game screen
    push offset CountApples                         ; push offset of CountApples
    call NumToAscii                                 ; Convert forom num to ascii
    push offset ObjectsDisplay                      ; push offset of ObjectsDisplay
    call UpdateDisplay
    push SECOND                                     ; 18 * 0.055sec = 1sec
    call Delay
    call ResetMouse                                 ; Reset mouse
    GameIn:
		; Apples fall -------------------------
        push cx                                     ; Backup
        mov cx, MANY_APPLES                         ; Many apples
		push offset Apple1
		push offset Apple2
		push offset Apple3
        FallApples:
            call MoveObjectDown
        loop FallApples
        pop cx                                      ; Restore
		; Check apples -----------------------
		push ax                                     ; Backup
		push bx
		push cx
        push si                                     ; Finish backup
		mov cx, MANY_APPLES                         ; Many apples
		mov bx, offset Apple1
        mov si, offset Bucket
		CheckApples:
			mov ax, [bx+2]                          ; move ax, y start
			add ax, [bx+6]                          ; add to ax, y size
			cmp ax, 182
			jne CheckApplesOnGround                 ; if !(ax >= 182), jump to CheckApplesOnGround
            ; Check if apple touch on bucket --------------------------------------------
            mov ax, [si]                            ; move ax x start of bucket
            cmp ax, [bx]
            ja CheckApplesOnGround                  ; if x start of bucket > x start of apple, jump to CheckApplesOnGround
            add ax, [si+4]                          ; Add ax x size of bucket
            mov si, [bx]                            ; move x start of apple to si
            add si, [bx+4]                          ; add x size of apple to si
            cmp ax, si
            jb CheckApplesOnGround                  ; if x size of bucket < x size of apple, jump to CheckApplesOnGround
			push [SoundLe]                          ; Push sound
            call Sound                              ; Play sound
            push ZERO                               ; minimum for random
			push 310                                ; maximun for random
			call Random                             ; return random num
			pop ax                                  ; random num
			mov [bx], ax                            ; insert the random num to bx(x start)
			mov [word ptr bx+2], APPLES_START_Y     ; move APPLES_START_Y to the y start of apple
            jmp InGameUpdateCount
        ; Check if apple touch in the ground ----------------------------------
        CheckApplesOnGround:
            cmp [word ptr bx+2], 190
            jb CheckApplesContinue                  ; if the y start of apple < 190, jump to CheckApplesContinue
            ; Show Apples in start game ---------------------------------------
            cmp [word ptr bx+4], ZERO
            jne CheckFailed                         ; if x size of apple != 0, jump to CheckFailed
            mov [word ptr bx+4], 10                 ; set x size of apple as 10
            mov [word ptr bx+2], APPLES_START_Y       ; set y start of apple as APPLES_START_Y
            jmp CheckApplesContinue
            ; Exit to ResetGame -----------------------------------------------
            CheckFailed:
            push SECOND                             ; Push 18 for proc Delay(18 * 0.055 sec = 1 sec)
            call Delay                              ; Wait 1 second
            jmp TheEndScreen                        ; jump to TheEndScreen
		CheckApplesContinue:
		add bx, 10                                  ; add 10 to bx to move the next apple
		loop CheckApples
		pop si                                      ; Restore
        pop cx
		pop bx
		pop ax                                      ; Finish restore
		; Move mouse -------------------------
		push ZERO
		push ZERO
		call GetLocationMouse                       ; Return x, y
		pop ax                                      ; y
		pop ax                                      ; x
		cmp ax, SCREEN_CORNER                        ; Corner of screen
		jb MoveMouseX                               ; if ax(y) < 270, jump to MoveMouseX
		MoveMouseMaximumX:
			mov [Bucket], SCREEN_CORNER              ; Maximun x for mouse, else the bucket is get out from screen
			jmp InGameDelay
		MoveMouseX:
			mov [Bucket], ax                        ; move bucket to x location of mouse
		InGameDelay:
		; Delay -------------------------
		push 1                                      ; 0.055sec
		call Delay                                  ; Delay for 0.055sec
        call DisableSpeaker                         ; Disable Speakers
        jmp InGameUpdateDisplay
		; Update count -------------------------
        InGameUpdateCount:                          ; Update score
		push offset CountApples
		call AsciiToNum
		push offset CountApples
		call AppendCount
		push offset CountApples
		call NumToAscii
        jmp CheckApplesContinue
		; Update display -------------------------
        InGameUpdateDisplay:
		push offset ObjectsDisplay                  ; push offset of ObjectsDisplay
		call UpdateDisplay
		; -------------------------
	jmp GameIn
    ; -------------------------------------------------------
	TheEndScreen:                                   ; The end screen
    push cx                                         ; Backup
    mov cx, PRINT_NULL_COUNT                          ; many print null
    PrintNull:
        push offset StringNull                      ; push offset of StringNull
        call PrintString                            ; Print StringNull
    loop PrintNull
    pop cx                                          ; Restore
	push offset PhotoEndArray                       ; Push offset of PhotoEndArray
	call PrintPhotoByArray                          ; Print photo
    push offset CountApples                         ; Push offset of CountApples
    call PrintString                                ; print count apples
    ; Reset game and objects --------------------------------
    ResetGame:
        ; Apple1 ------------------
        mov [Apple1], X_START_APPLE1
        mov [Apple1+2], APPLES_START_Y
        mov [Apple1+4], ZERO
        ; Apple2 ------------------
        mov [Apple2], X_START_APPLE2
        mov [Apple2+2], Y_START_APPLE2
        mov [Apple2+4], ZERO
        ; Apple3 ------------------
        mov [Apple3], X_START_APPLE3
        mov [Apple3+2], Y_START_APPLE3
        mov [Apple3+4], ZERO
        ; Bucket ------------------
        mov [Bucket], X_START_BUCKET
        ; Count apples ------------
        push bx                                     ; Backup
        push cx                                     ; Finish backup
        push offset CountApples                     ; push offset of CountApples
        call StringLenght                           ; Return lenght of string
        pop cx                                      ; Lenght of string
        lea bx, [CountApples]                       ; move offset of CountApples to bx
        ResetApplesCount:
            mov [byte ptr bx], ZERO                 ; Reset [Byte ptr bx]
            inc bx                                  ; bx++
        loop ResetApplesCount
        pop cx                                      ; Restore
        pop bx                                      ; Finish restore
    ; -------------------------------------------------------
    TheEndScreenInputKey:
    push ZERO
    call InputKey                                   ; Wait for input fron keyboard and return key
    pop ax                                          ; key
    cmp ax, 'e'
    je exit                                         ; if key == 'e', jump to exit
    cmp ax, 'h'
    jne TheEndScreenInputKey                        ; if key != 'h', jump to TheEndScreen
    call GraphicMode                                ; Reset screen
    jmp HomeScreen                                  ; jump to HomeScreen


exit:
    call GraphicMode                                ; Reset screen
    mov ax, 4c00h
    int 21h
END start