; Participant teacher: Jacob Shutzman / Final Countdown game
;----------------------------------------------------------------------------------------------------+
; List of procs and their function  (Game's Extras are noted for beautifying the game)               |
;----------------------------------------------------------------------------------------------------+
;                                                                                                    | 
; strnum   - Uses a memory location loaded into di by the calling module, to get a string of         |
;            numbers (in ASCII), and turns it into a number placed in dx.  (strnumber is better)     | 
;                                                                                                    | 
;                                                                                                    | 
; duration - Asks the player how many seconds he/she wants to play. converts the given               |
;            input from ASCII to a number and places it in outputn  (1 Extra).                       |
;                                                                                                    | 
; dispwelc - Display welcome screen - Opening screen + game instructions (2 Extras).                 |
;            It checks if the user wants to play, if not. it gets out. It also asks if               |
;            the user wants a color background for the game. If the answer is 'y', it stores         |
;            the 'y' in scrncol, for the 'background' proc to examine.                               |
;                                                                                                    | 
; genrnd   - Gets as a parameter an upper limit for random generation.This proc uses                 |
;            1/100th of a second from the clock, and explained more in details bellow.               |
;            It returns the random number in dx (between 0 and the boundary.)                        | 
;                                                                                                    | 
; delay1   - Used by genrnd to wait for couple of tics, in order for the random to be                |
;            better. (one parm - delay amount). Each tic is 1/18th of a second.                      |
;                                                                                                    | 
; delay2   - This is the heart of the game. It delays the game between drawing and erasing           |
;            of the squares, in which period, it 'haunts' the mouse-click. If clicked (left)         |
;            it calls mousecapture to detect where the click occured.                                |
;                                                                                                    | 
; mousecapture - If the mouse clicked inside the square, increment the points count and beep         |
;                (noparms).                                                                          | 
;                                                                                                    | 
; number2string - Convert a number to displayable format (ASCII) - no parms. Works on                |
;                 memory location : numstr.                                                          |
;                                                                                                    | 
; dollar     - Prepares memory location with $ signs, helper for number2string.                      |
;                                                                                                    | 
; soundplay  - Make the 'beep' sound when a square is hit by the mouse.  (no parms).                 |
;                                                                                                    | 
; drawsq     - gets one parameter which is a color. draws a square with upper left corner            |
;              being the X , Y coordinates, generated by genrnd.                                     |
;                                                                                                    | 
; drawline   - A helper proc for drawsq. It draws one line, a pixel at a time with 10h               |
;              interrupt.                                                                            |
;                                                                                                    | 
; background - Colors the background for the squares with some 'bizarre' color - for fun,            |
;              upon the player's request.                                                            |
;                                                                                                    |                                                                         
; drawone    - (The pair background/drawone are essentially identical to drawsq/drawline,            |
;              with the exception of painting the whole screen. I could have used parameters,        |
;              however, I wanted it to be more obvious (sometimes redundant code is beauty :-)       |
;                                                                                                    | 
; soundstop  - Stops the sound after the square changes.                                             |
;                                                                                                    | 
; gameloop   - Literally the game's loop. calls genrnd to give X and Y for the next square,          |
;              calls delay2, erases the screen preparing for the coming square and stops             |
;              the 'beep', if a hit was made.                                                        |
;                                                                                                    | 
; newline    - Since placing a new line is so common in my code, I decided to make it a proc.        |
;              Also replaces the cryptic format of the interrupt and better code organization.       |
;                                                                                                    |     
; hex2dec    - Receive input in ax as hex, return a string of the decimal equivalent referenced by si|
;              We point si to a '$$..' string, which will contain the result.                        |
;                                                                                                    |
; calcpercent- Since I give the option to play different length games, I need to calculate the score |
;              in percentage, to give the player a better estimate of her achievement, and not only  |
;              the number of hits. This proc does that.                                              |
;                                                                                                    |
; The program is easily customizable, to change square size - sqsz, colors: red, blue                |                                                                                                    |
;                                                                                                    |
; Added another extra : RECORD FILE. The main processing for it starts after the line that says:     |
; RECORD FILE manipulations.                                                                         |
; I list here all the supporting procs for it. Some are obvious, so no explanation is needed, like   |                    
; readfile, writefile etc. This portion was added to beautify the game, so it occurs after the game  |
; had been played. (some of the procs are customization of existing procs, for example strnumber is  |                                                                                   |
;                   a more versatile version of strnum, which essentially makes strnum obsolete, but |
;                   I tried not to touch the working code for the game,so I left both. In a perfect  |
;                   world I'd keep the more robust only and change the calls.                        | 
;                                                                                                    | 
;  'supporting cast' for the record file:                                                            |
;  --------------------------------------                                                            |
;  createfile , readfile, openfile, closefile , dollar1 - more robust than dollar.                   |
;                                                                                                    |          
;  pertostr - converts percent format xxx.yy%  to xxxyy, for later turning it to a number for        |
;             comparison of new result with the existing record.                                     |
;  len      - calculates the length of the percentage string (could be 100% which makes it one char  |
;             longer (in order to know what how many bytes to write to the record file.              |   
;                                                                                                    | 
;  Finally, the delayloop variable warrants some explanation for its value of 30,000. It was chosen  |
;  by me for two reasons. It delays the game enough to give you a chance to hit, but still not such  |
;  a great chance. If you score in the 90%, you are damn good with coordination. The other reason was|
;  after trial and error, I realized it approximates one square per two seconds of the game, which   |
;  lets me get away with not measuring time with the clock, so a 40 seconds would yield 20 square    |  
;  game.                                                                                             | 
;                                                                                                    | 
;----------------------------------------------------------------------------------------------------+
IDEAL
MODEL small
STACK 600h
DATASEG
x             dw    ?
y             dw    ? 
rndnums       db   '02173514869712304859681234605973571204986634127098'    ; for random gen
clock         equ  es:6ch
digs          db   4
rndstr        db   '$$$$$'
size1         equ  4
rndlimit      equ  50
clocktic      equ  18
rndupper      dw   ? 
vardec        dw   10
scrh          equ  310
scrv          equ  190
sqsz          equ  4 
red           equ  4      ;color I chose for the squares
blue          equ  10     ;I'm not color-blind, but did not know the name for this, it's nice though 
delayloop     equ  30000  ;How fast u want the game to be? lower number means faster
msgsz         equ  61
stars         db   '                              *                           $',13,10
              db   '                             ***                          $',13,10
              db   '                            *****                         $',13,10
              db   '                           *******                        $',13,10
              db   '                          *********                       $',13,10

msg           db   ' ****** Welcome to the final CountDown Challenge!!! ******$'
grules        db   'You need to chase the square with the mouse and click     $',13,10
              db   'with the left mouse button. Every time you click the      $',13,10
              db   'square, you get one point. If you got it, a beep sounds.  $',13,10
              db   'U also get to choose how many seconds to play.            $',13,10
askgame       db  ' Would you like to play the game ? (y -for yes, n -for No)  $'
durationm     db  ' How many seconds do you feel like playing (20 - 180) ?  $' 
bkgrnd        db  ' Do you want color background    ? (y -for yes, n -for No) $'
nogame        db  ' User decided NOT to play $' 
scorem        db  ' Your final score is:       out of $$$$$'
scorep        db  ' Your score in percentage is:  $$$$$$$$'
points        db  0
totsquares    db  0
numstr        db  '$$$$$'     ;STRING FOR 4 DIGITS. 
currfactor    db  ? 
numasc        db  ?  
inputn        db  6 dup(?)
outputn       db  0
scrncol       db  ' '
pcfactor      db  100 
num           db  ?
res           db  5 dup ('$')
fullper       db  8 dup ('$')   
newscorenms   db  6 dup('$')     ;for comparison with record
result1       db  '$$$$$$'
recordholder  db  ' You, my friend, IS the Record Holder now!!!',10,13,'$'  
congrats      db  ' Congratulations buddy !!! You have just broken the record.',10,13,'$' 
recordstays   db  ' Sorry, you have not broken the record !!!',10,13,'$'
filename      db  'record.txt',0
filehandle    dw  ?
errormsg      db 'Error',10,13,'$' 
numofbytes    equ 7
oldscore      db  '$$$$$$$$'

CODESEG
;-----------------------------------------------------------------------------------------------------
proc          pertostr
scorecheck:
              mov  al,[si]
              cmp  al,'$'
              je   donewithit
              cmp  al,30h
              jb   nextchar                  ; both dot and % ASCII's are < 30h
              mov  [di],al
              inc  si
              inc  di
              jmp  scorecheck
nextchar:     inc  si
              jmp  scorecheck              
donewithit:   ret 
endp          pertostr 

;-----------------------------------------------------------------------
proc          strnumber
;count how many digits we have
              xor  ax,ax
              xor  bx,bx
              push di
countloop:     
              mov  bl,[di]
              cmp  bl,'$'
              je   updatesize
              inc  al
              inc  di
              jmp  countloop
updatesize:
              pop  di
              mov  [size1],al
              xor  cx,cx
              mov  cl,[size1]
              mov  bx,1
              xor  dx,dx
              xor  ax,ax
              add  di,cx
              sub  di,1
loop1:              
              mov  al,[di] 
              mov  ah,0
              sub  al,30h
              push dx 
              mul  bx
              pop  dx 
              add  dx,ax
              mov  ax,bx
              push dx
              mul  [vardec]
              pop  dx 
              mov  bx,ax
              dec  di
              loop loop1 
              ret
endp          strnumber              
;-----------------------------------------------------------------------------------------------------
proc          createfile 
              mov bx,1                     ; bx=1 means create failed
              mov ah,3Ch
              mov cx,0              
              mov dx, offset filename
              int 21h 
              jc  nosuccess
              mov bx,0
              mov [filehandle],ax    
nosuccess:    ret
endp          createfile
;-----------------------------------------------------------------------------------------------------
proc          openfile                   ; bx=0 open succeeded, bx=1 file does not exist
              mov  bx,0                  ; bx=2  other error with the file
              mov  ah,3Dh
              mov  al,2
              lea  dx,[filename]
              int  21h
              jc   openerror
              mov  [filehandle],ax
              ret
openerror:  
              mov   bx,1
              cmp   ax,2               ; ax==2 File not found
              je    endit
              mov   bx,2               ; Other error than file not found             
endit:        ret
endp          openfile
;-----------------------------------------------------------------------------------------------------
proc          readfile
              mov ah,3Fh
              mov bx,[filehandle]
              mov cx, numofbytes
              mov dx,offset oldscore
              int 21h     
              ret  
endp          readfile 
;-----------------------------------------------------------------------------------------------------
proc          writefile                ; Receives a parameter - how many bytes to write
              push bp
              mov  bp,sp
              mov  ah,40h
              mov  bx,[filehandle]
              mov  cx,[bp+4]           ; length of string to write
              mov  dx, offset fullper
              int  21h
              pop  bp
              ret  2  
endp          writefile 
;-----------------------------------------------------------------------------------------------------
proc          closefile
              mov ah,3Eh
              mov bx,[filehandle]
              int 21h
              ret  
endp          closefile 
;-----------------------------------------------------------------------------------------------------
proc          dollars1                  ;No parms. Fills area in memory with "$"  
              push cx
              push di              
              mov  cx, 7
              mov  di, offset result1
dollars_loop: mov  bl, '$'      
              mov  [ di ], bl
              inc  di
              loop dollars_loop
              pop  di
              pop  cx	
              ret
endp          dollars1
;-----------------------------------------------------------------------------------------------------
proc          len
              xor  dx,dx
              xor  al,al
checkch:      mov  al,[si]
              cmp  al,'$'
              je   returnlen 
              inc  si
              inc  dx 
              jmp  checkch 
returnlen:    ret
endp          len 
;-----------------------------------------------------------------------------------------------------  
proc          hex2dec                  ;works on value in ax, returns result in the area si references     
              mov  cx,0
              mov  bx,10
onedig:       mov  dx,0
              div  bx                  ; ax = dx:ax / bx (quotient ,  dx = mod( dx:ax, bx)
              add  dl,30h              ; make the decimal digit its ASCII value
              push dx
              inc  cx
              cmp  ax,9                ; Last digit when ax <= 9 
              jg   onedig 
              add  al,30h
              mov  [si],al             ; First digit    
getdig:       pop  ax                  ; Loop on the rest of the digits stored on the stack
              inc  si
              mov  [si],al
              loop getdig
              ret
endp          hex2dec  
;-----------------------------------------------------------------------------------------------------
proc          calcpercent          ; calculate percentage hits/total-squares up to 2 decimals accuracy      
              push bp
              mov  bp,sp 
              xor  bx,bx        
              mov  ax,[bp+4]           ; number of hits
              mov  bl,[bp+6]           ; total squares
              mul  [pcfactor]
              div  bl                  ; al = quotient, ah = remainder 
              mov  [num],al
              push bx
              push ax                  ; save results on the stack 
              xor  ax,ax
              mov  al,[num]            ; First the integer part
              mov  si, offset res
              call hex2dec             ; put result in res          
              mov  bx, offset res      ; Transfer integer portion to final string
              xor  si,si
              mov  di, offset fullper
              xor  dx,dx
loop10:       mov  dl,[bx+si]
              cmp  dl,'$'
              je   goahead 
              mov  [di],dl
              inc  si
              inc  di
              jmp  loop10
goahead:      mov  [byte ptr di],'.'
              inc  di                          
              pop  ax                   ; now the fraction
              pop  bx      
              mov  al,ah          
              xor  ah,ah
              mul  [pcfactor]
              div  bl
              xor  ah,ah
              call dollars              ; reset numstr to 5 $ signs
              mov  si, offset numstr
              call hex2dec              ; (input in ax) put result in numstr              
              xor  si,si
              mov  bx, offset numstr
loop2:        mov  dl,[bx+si]
              cmp  dl,'$'
              je   done 
              mov  [di],dl
              inc  si
              inc  di
              jmp  loop2              
done:      
              mov  [byte ptr di],'%'                                     
              pop  bp
              ret  4
endp          calcpercent
;-----------------------------------------------------------------------------------------------------
proc          drawone                  
              push bx
              mov  bx,320
oneline:              
              mov  ah,0ch  
              int  10h 
              inc  cx
              dec  bx
              cmp  bx,0
              jnz  oneline
              pop  bx
              ret  
endp          drawone  
;-----------------------------------------------------------------------------------------------------             
proc          background                ; 1 parameter - color
              push bp
              mov  bp,sp 
;Save registers state               
              push ax
              push bx
              push cx
              push dx               
              mov  al,[bp+4]            ; color
              mov  bx,200
              mov  cx,0
              mov  dx,0
drlines:              
              call drawone
              inc  dx
              mov  cx,0
              dec  bx
              cmp  bx,0
              jnz  drlines              ;loop on lines, creates the square
;Restore registers
			  pop  dx
			  pop  cx
			  pop  bx
			  pop  ax 
			  pop  bp
			  ret  2
endp          background
;-----------------------------------------------------------------------------------------------------
proc          newline
              push ax
              push dx
    		  mov  ah,2               
			  mov  dl,10
			  int  21h
			  pop  dx
			  pop  ax
			  ret
endp          newline			   
;-----------------------------------------------------------------------------------------------------
proc          graphicsmouse              ; Enter graphics mode, initial and show the mouse
              push ax
              mov  ax,13h
              int  10h 
              cmp  [scrncol],'y'
              jne  nocol 
              push blue
              call background            ; Player asked for colorfull background 
nocol:              
              mov  ax,0h
              int  33h
              mov  ax,1h
              int  33h 
              pop  ax
              ret 
endp          graphicsmouse

;-----------------------------------------------------------------------------------------------------
; Calculate the duration in seconds (convert ASCII to number)
proc          duration               
              mov  dx, offset durationm   
              mov  ah,9h
              int  21h    
              call newline           	
              mov  dx, offset inputn
              mov  bx, dx
              mov  [byte ptr bx],4
              mov  ah, 0Ah
              int  21h
; The input number of seconds resides starting at: [inputn+2] 
; its length is in [inputn+1] 
              xor  cx,cx
              mov  cl,[byte ptr inputn+1]  ;length of input number in input buffer
              xor  si,si
              xor  bx,bx  
              mov  bx, offset inputn
              add  bx,2                    ;bl points to the beginning of the input               
              xor  al,al              
nextdig:      
              mov  al,[bx+si]
              mov  [numstr+si],al
              inc  si
              loop nextdig
              mov  di, offset numstr
              call strnum                  ; string num into num
              mov  [outputn],dl                        
              ret                          ;outputn will have the result
endp          duration
;-----------------------------------------------------------------------------------------------------
proc          delay1                       ; delays execution by parameter X 1/18th of a second
              push bp
              mov  bp,sp 
              xor  cx,cx
              mov  cx,[bp+4]               ;delay amount as parameter
              mov  ax,40h
              mov  es,ax                                                                        
tick:         mov  ax,[clock]
notick:       cmp  ax,[clock]              ; Wait for a clock tic
              je   notick               
              loop tick 
              pop  bp
              ret  2           
endp          delay1
;-----------------------------------------------------------------------------------------------------
proc          delay2                       ; delays execution by parameter (loop counter)
              push bp
              mov  bp,sp 
              push cx
              xor  cx,cx
              mov  cx,[bp+4]               ;loop amount                                   
ticktack:     
              push cx     
              xor  ax,ax  
              xor  bx,bx
              xor  cx,cx
              xor  dx,dx
              mov  ax,3h
              int  33h
              cmp  bx,1                    ;catch the mouse if clicked
              jne  proceed        
              call mousecapture   
proceed:                 
              pop  cx   
              loop ticktack
              pop  cx 
              pop  bp
              ret  2           
endp          delay2
;-----------------------------------------------------------------------------------------------------
proc          strnum                      ;Turns a string of digits into a number in dx
              mov  cx,size1               ;Up to 4-digit number
              mov  bx,1
              xor  dx,dx
              xor  ax,ax
              add  di,cx
              sub  di,1
digits:              
              mov  al,[di]
              cmp  al,'$'                 ;We start from the right digit, if it's a $
              je   nextd                  ;we skip (number shorter than 4 digits)
              mov  ah,0
              sub  al,30h
              push dx 
              mul  bx
              pop  dx 
              add  dx,ax
              mov  ax,bx
              push dx
              mul  [vardec]
              pop  dx 
              mov  bx,ax
nextd:        dec  di           
              loop digits 
              ret
endp          strnum 
;----------------------------------------------------------------------------------------------------+
proc          genrnd                 ;Using the 1/100s of the clock for indexing into a digit string |
;----------------------------------------------------------------------------------------------------+
; Get upper limit and rnd number string as parameters.The proc always creates a 4-digit number based |
; on the clock (1/100s) and a string of digits. We need randoms for positioning pixels on the screen.|
; We need numbers between 0-200 (vertical),  and 0-320 (horizontal) actually 0 to 190  and 0-310     |
; because that coordinate would be the upper left corner of our game square.                         |
;----------------------------------------------------------------------------------------------------+
              push bp
              mov  bp,sp
              mov  bx,[bp+4]               ; upper limit for random 
              mov  [rndupper],bx 
              xor  cx,cx
              mov  cl,[byte ptr digs]      ;number of digits = loops for new time reading
              mov  di,offset rndnums
              mov  si,offset rndstr        ;the generated number will be stored here (as a string) 
 rndloop:     push cx                      ;every loop generates one digit 
              mov  ah,2Ch                  ;ch- hr , cl - min, dh -sec   dl - 1/100s
              int  21h
              mov  bl,rndlimit             ;rndlimit is one more than the largest index generated
              xor  ax,ax
              mov  al,dl                   ;(0 to 99)
              div  bl                ;ah has the random (ah= al mod bl) < 50 [len(digit string)=50]
;---------------------------------------------------------------------------------------------------
; Use ah as index into rndnums, picking digits for a random number
;---------------------------------------------------------------------------------------------------
              xor  bx,bx
              mov  bl,ah  
              mov  al,[di+bx]
              mov  [si],al                 ;build random number in memory 
              inc  si 
              push 2                       ;delay by 2 clock cycles (parameter for delay1)
		      call delay1            
		      pop  cx
              loop rndloop	
; Turn the string of random into a number limited by the parameter.
              mov  di,offset rndstr
              call strnum                  ;dx gets the resulting number limited by rndupper 
              mov  ax,dx
              xor  dx,dx
              mov  bx,[rndupper]
              div  bx                               
              pop  bp
              ret  2
endp          genrnd
;-----------------------------------------------------------------------------------------------------
proc          drawline                     ;draw individual line length sqsz
              push bx
              mov  bx,sqsz
nextpix:      mov  ah,0ch  
              int  10h 
              inc  cx
              dec  bx
              cmp  bx,0
              jnz  nextpix
              pop  bx
              ret  
endp          drawline  
;-----------------------------------------------------------------------------------------------------             
proc          drawsq                       ; 1 parameter - color
              push bp
              mov  bp,sp 
;Save registers state               
              push ax
              push bx
              push cx
              push dx               
              mov  al,[bp+4]               ; color
              mov  bx,sqsz
              mov  cx,[x]
              mov  dx,[y]
lineloop:     call drawline
              inc  dx
              mov  cx,[x]
              dec  bx
              cmp  bx,0
              jnz  lineloop                ;loop on lines, creates the square
;Restore registers
			  pop  dx
			  pop  cx
			  pop  bx
			  pop  ax 
			  pop  bp
			  ret  2
endp          drawsq
;-----------------------------------------------------------------------------------------------------
proc          dispwelc                     ; Display welcome screen
              push ax
              push si
              push bx  
              xor  si,si 
              mov  cx,5 
promo:        mov  dx,offset stars         ;print the stars for fun 
              add  dx,si                    
              mov  ah,9h
              int  21h   
              call newline              
			  add  si,msgsz
			  loop promo
			  call newline               
;Print welcome message   
              mov  dx, offset msg   
              mov  ah,9h
              int  21h  
              call newline  
              call newline            			  
;print the stars upside down			  
              mov  cx,5 
              mov  bl,4
promodown:    mov  dx,offset stars
              mov  al,msgsz
              mul  bl
              add  dx,ax
              mov  ah,9h
              int  21h 
              call newline              
			  dec  bl
   			  loop promodown
   			  xor  si,si 
              mov  cx,4   			  
gamerules:    mov  dx,offset grules       ;print the game rules 
              add  dx,si                    
              mov  ah,9h
              int  21h 
              call newline             
			  add  si,msgsz
			  loop gamerules    			  
   			  call newline    			  
;Ask if the user wants to play   
              mov  dx, offset askgame   
              mov  ah,9h
              int  21h 
              call newline               				  			  	  
; Receive input from the keyboard 
              mov  ah,0Ch
              mov  al,07h
              int  21h                                     
              cmp  al,'y'                 ;'y' means the user wants to play
              je   play
              mov  dx,0
play:          
              mov  dx, offset bkgrnd      ;Ask if the player wants a colorfull screen 
              mov  ah,9h
              int  21h 
              call newline
              call newline
              mov  ah,0Ch
              mov  al,07h
              int  21h                                     
              mov  [scrncol],al                           
              pop  bx
              pop  si
              pop  ax     
              ret  
endp          dispwelc 
;-----------------------------------------------------------------------------------------------------
proc          number2string  
              push cx
              call dollars               ;prepare numstr with $ signs.
              mov  bx, 10                ;extracting a digit at a time
              mov  cx,0    
;EXTRACT DIGITS               
cycle1:       mov  dx,0                  ;to facilitate division       
              div  bx                    ;dx:ax / 10 =  ax - quotient  dx -remainder 
              push dx                    ;using a stack will allow fetching in the correct order 
              inc  cx        
              cmp  ax,0                  ;done if number is zero
              jne  cycle1     
;Retrieve pushed digits (opposite order)
              mov  si, offset numstr
cycle2:       pop  dx           
              add  dl,48                 ;convert dec digit to ASCII - 48 is '0' in ASCII 
              mov  [si],dl
              inc  si
              loop cycle2  
              pop cx
              ret
endp          number2string 
;-----------------------------------------------------------------------------------------------------
proc          dollars                    ;No parms. Fills area in memory with "$"  
              push cx
              push di              
              mov  cx, 5
              mov  di, offset numstr
loop_dollars: mov  bl, '$'      
              mov  [ di ], bl
              inc  di
              loop loop_dollars
              pop  di
              pop  cx	
              ret
endp          dollars
;-----------------------------------------------------------------------------------------------------
proc          soundplay	                ;Play sound, for hitting a point
	          push ax
	          mov  al,10110110b         ; "magic" number    
	          out  43h,al               ; send it to initialize the 43h port of timer 2
	          mov  ax,4560   	        ; Middle C note frequency (especially annoying beep)	
	          out  42h,al               ; low order byte to port 42h
	          mov  al,ah
              out  42h,al               ; high order byte of ax to port 42h	          
	          in   al,61h
	          or   al,00000011b         ;turn speaker on by forcing bit 0 and 1 to be 1's
	          out  61h,al
	          pop  ax
	          ret
endp          soundplay
;-----------------------------------------------------------------------------------------------------
proc          soundfoul	                ;Play sound, for missing a point
	          push ax
	          in   al,61h
	          or   al,00000011b       
	          out  61h,al
	          mov  al,0b6h
	          out  43h,al
	          mov  ax,1200   	      
	          out  42h,al
	          mov  al,ah
              out  42h,al
	          pop  ax
	          ret
endp          soundfoul
;-----------------------------------------------------------------------------------------------------
proc          soundstop	                ;stop playing sound
	          push ax
	          in   al, 61h
	          and  al, 11111100b        ; Forcing bits 0 and 1 to zero, to turn off sound
	          out  61h, al
	          pop  ax
	          ret
endp          soundstop
;-----------------------------------------------------------------------------------------------------
proc          gameloop                     
showsq:       push cx              
              mov  ax,scrh 
              sub  ax,sqsz             
              push ax
              call genrnd               ;Use random generator to get coordinates on the screen                                     
              mov  [x],dx
              mov  ax,scrv
              sub  ax,sqsz              
              push ax
              call genrnd
              mov  [y],dx   
;Draw square                                                                        
              push red 
              call drawsq               ;Draw a square with x,y top-left pixel , size sqsz
              inc  [totsquares]              
              mov  cx,8	                ;delay between drawing and erasing the square
deloop:       push delayloop                       
              call delay2   
;stop sound  
              call soundstop                                     
              loop deloop
;Erasing the screen by re-entering Graphics mode and showing the mouse
;----------------------------------------------------------------------------------------------------
erase:
              call graphicsmouse             
              pop  cx
              loop showsq   
              ret
endp          gameloop              
;-----------------------------------------------------------------------------------------------------
proc          mousecapture            ;Check if mouse clicked on the square                                 
              shr  cx,1               ;Horizontal value calculation (divide cx by 2)
              cmp  cx,[x]
              jb   next1              ;clicked left of the square
              sub  cx,[x]
              cmp  cx,sqsz
              ja   next1              ;clicked right of the square
              cmp  dx,[y]
              jb   next1              ;clicked above the square
              sub  dx,[y] 
              cmp  dx,sqsz
              ja   next1              ;clicked below the square
              inc  [points]           ;click inside the square - gets a point  
              call soundplay
              call graphicsmouse      ; Initial graphics/mouse to prevent duplicates score counting                                                    
next1:       
              ret
endp          mousecapture

;*****************************************************************************************************
; MAIN PROGRAM                                                                                       *
;*****************************************************************************************************
start:        mov  ax,@data
              mov  ds,ax              
;Ask if the user wants to play the game    (Display the welcome screen)          
              call dispwelc             ; if dx=0 after this, the user does not want to play
              cmp  dx,0
              jne  playon
              jmp  endgame             
playon:       call duration             ; returns seconds in: outputn  (ask how long of a game)
                                        ; 
              xor  cx,cx
              mov  cl,[byte ptr outputn]   
              shr  cl,1                 ; 1 square per 2 seconds (so secs/2)             
;Get into Graphics mode, Initial mouse and show it
              call graphicsmouse        ;Initialization                        
              call gameloop             ;Process                           
                                        ;Wrap-up - exiting the game & returning to text mode                                    
              mov  ah,0
              mov  al,2
              int  10h  
;print points with a message out of total squares (to show its quality)			  
              mov  al,[points]
              call number2string        ;takes the number in al and returns ASCII in numstr 
              call newline			  
			  mov  si, offset numstr
			  mov  di, offset scorem
			  add  di,22
			  mov  cx,5                 ;move the score to its proper place
mvnum:		  
              mov  al,[si]
              cmp  al,24h
              jne  realnum
              mov  al,' '
realnum:	  
              mov  [di],al
			  inc  si
			  inc  di
			  loop mvnum			  
			  mov  al,[totsquares]
              call number2string         
              call newline			  
			  mov  si, offset numstr
			  mov  di, offset scorem
			  add  di,35
			  mov  cx,4                 ;move the total squares to its proper place
totnum:		  
              mov  al,[si]
			  mov  [di],al
			  inc  si
			  inc  di
			  loop totnum			  			  			  
              mov  dx, offset scorem   
              mov  ah,9h
              int  21h 
              call newline   
;calculate score percentage  
              xor  ax,ax
              xor  bx,bx
              mov  al,[totsquares] 
              mov  bl,[points]  
              push ax
              push bx                                      
              call calcpercent          ; Percentage goes to: fullper 
             
			  mov  si, offset fullper              
              mov  di, offset scorep
			  add  di,31 
			  mov  cx,8                 ;move calculated percentage into the message
percentl: 			  
              mov  al,[si]
			  mov  [di],al
			  inc  si
			  inc  di
			  loop percentl
              mov  dx, offset scorep   
              mov  ah,9h
              int  21h 
              call newline               
              
; RECORD FILE manipulations (added at the end to make the game more challenging) 
;----------------------------------------------------------------------------------------------------+
; The record so far (in percentage is kept in te file: record.txt If there are no scores yet, there  |
; is no file. So the file is created the first time a player plays the game. If the record is broken |
; I update the file with the new score, otherwise the record stays.                                  |             
;----------------------------------------------------------------------------------------------------+  

              call openfile              ; check if record file exists                                       
              cmp  bx,2                  ; fatal error (other than file NF) - just end gracefully.
              je   exit
              cmp  bx,1                  ;bx=1  file not found
              je   createit
              call readfile              ;record exists (read it into oldscore)              
;Turn oldscore into a number
              mov  si, offset oldscore
              mov  di, offset result1
              call pertostr
              mov  di,offset result1
              call strnumber             ;dx gets the number of record file score 
              mov  ax,dx
              push ax                    ;save record score on the stack 
;reset result1 and prepare it for new score
              call dollars1         
;Turn newscore (in fullper) to a number
              mov  si, offset fullper
              mov  di, offset result1
              call pertostr
              mov  di,offset result1
              call strnumber              ;dx gets the number of new score          
              pop  ax                     ;get back record score for comparison 
              cmp  dx,ax
              jb   stays                  ;record in file is higher                                   
              mov  dx, offset congrats    ;message - record broken   
              mov  ah,9h
              int  21h                 
;erase, re-create the file.
              mov  dx,offset filename 	 
              mov  ah,41h 	        	  ; function 41h - delete file
              int  21h 		              
              call createfile                
              mov  si, offset fullper     ; calculate size of string to write
              call len                    ; puts the length of fullper in dx
              push dx        
              call writefile          
              jmp  cls                        
createit:                                 ;no scores yet (establishing initial record)   
              call createfile 
;The user has the record (first time she played)
              mov  dx, offset recordholder   
              mov  ah,9h
              int  21h  
              mov  si, offset fullper     ; calculate size of string to write
              call len                    ; puts the length of fullper in dx
              push dx                                                 
              call writefile              ;writes new score
              jmp  cls              
stays:                   
              mov  dx, offset recordstays   
              mov  ah,9h
              int  21h                
cls:          call closefile 

;End record file manipulations                                                    			                
              jmp  exit                          
endgame:      
              mov  dx, offset nogame  
              mov  ah,9h
              int  21h
              call newline                                                                           
;-----------------------------------------------------------------------------------------------------                                 	                 
exit:         mov  ax, 4c00h
              int  21h
END start
    