;  Welcome to Columns v3.0, (c) Mel Tsai!

;  To play this game, select the difficulty level using the left and right
;  buttons.  After this, you must turn the calculator on its side, and use
;  the arrow keys to move and the "2nd" key to flip the block (I've found
;  that it is easiest to play with the left hand holding the calculator and 
;  the right index and middle fingers controlling the arrow keys, with the 
;  thumb pressing 2nd).

;  The "more" key pauses and the "exit" key exits.  To "warp out" and save 
;  your game in the current position, simply press "enter".  The next time  
;  you start columns, press "more" to set the blocks back in motion.

;  Simply match 3 or more blocks in a row (horizontally, vertically, or 
;  diagnally) to increase your score!  Every 255 blocks, your level will
;  be increased (to a maximum of level 9).

;  Since the calculator screen is small, I wanted to utilize more screen 
;  space for this game so it would be easier to see.  This is why everything
;  is turned on its side.  


;  This is the assembly source to the original Columns game.  Please don't
;  modify this source unless you don't plan to distribute it.  Also, don't 
;  "cut and paste" from this unless I'm given appropriate credit in your
;  program.  However, you can take ideas from this and use them, as long as
;  you aren't merely copying!  That's the reason why I'm releasing this.

;      If you have any improvement ideas for this game, mail me at 
;      tsaimelv@pilot.msu.edu and I may just do it, and I'll give you credit.
;      I have, however, pretty much stopped all development in this game.

;  Thanks to Magnus Hagander's TEXAN.ASM for helping me with figuring out
;  some of the zshell programming techniques!

;  This is my first program, it is in no way optimized, it's not well 
;  documented, and it may be difficult to understand some parts.  
;  Again, send any comments/questions/bug reports/game ideas/etc. to 
;  tsaimelv@pilot.msu.edu.

;  Changes from Columns v2.0:

;  1.  Fixed the "infinite blocks" bug.

;  2.  Added a "super block" in which whatever block type it lands on,
;  all of those blocks on the screen will disappear.  The block will come
;  down approximately 2% of the time, more or less.

;  3.  Added 2 new levels of difficulty, "Very Hard" and "Impossible."
;  Very Hard has 7 different blocks and Impossible has 8 (the original
;  "easy" level has 4, "medium" has 5 and "hard" has 6).

;  4.  Added an Instruction page so people won't get confused...

;  5.  Added 2 speed levels for a maximum speed level of 9 (instead of
;  the original 7).

;  6.  Made it so that your level will increase every 127 blocks instead
;  of 256.  Hopefully this will get rid of those 1 hour games...

;  7.  I tried to optimize the game to make it smaller, but it's not much
;  of an improvement.  The new features just add so much space that the
;  improvements are hidden...


#INCLUDE "TI-85.H"

.org 0
.db "Columns v3.0", 0

DEFINITIONS:                            

; Block memory structure: I organized it so that the bottom left block (1,1)
; type is stored at $80DF, the top left block (16,1) at $80EE, the bottom
; right block (1,7) at $813F and the top right block (16,7) at $814E.
; This way each column takes up 16 bytes, i.e. block (1,2) is stored at
; $80EF, which is 1 plus block (16,1).

; vars start at $814F, after block mem. 

BlocksTotal = $814F                     ; (2 bytes) 16 bit score.
BlocksTotalTemp = $8151                 ; (2 bytes) used for comparison. 

Score1 = $8153                          ; 5 bytes unpacked from BlocksTotal,
Score2 = $8154                          ; displayed on screen as current score.
Score3 = $8155 
Score4 = $8156 
Score5 = $8157 

TopType = $8158                         ; used for holding 3 current block 
MidType = $8159                         ; types.
BottomType = $815A

LevelCurrent = $815B                    ; stores level, 1 through 7.
LevelString = $815C                     ; ASCII string of Level_Current.

Ypos = $815D                            ; Y position of current bottom block.
Xpos = $815E                            ; X position of current bottom block.

Blocknum = $815F                        ; game difficulty, equals 4,5,6,7,or 8

SuperTemp = $8160                       ; signifies super block

SaveAF = $8161                          ; This is used for KEYLOOP_B
SaveAF2 = $8162

DelayTemp = $8163                       ; Saves delay variable
DelayTemp2 = $8164

TopTemp = $8165
MidTemp = $8166
BottomTemp = $8167

Initial1 = $8168                        ; three stored initials.
Initial2 = $8169
Initial3 = $816A
                                        ; Temporary Storage.
Temp1 = $816B                           ; These are mostly used as 2 byte
Temp2 = Temp1+1                         ; variables, spilling over to the next
Temp3 = Temp2+1                         ; byte.
Temp4 = Temp3+1
Temp5 = Temp4+1
Temp6 = Temp5+1
Temp7 = Temp6+1
Temp8 = Temp7+1
Temp9 = Temp8+1
Temp10 = Temp9+1
Temp11 = Temp10+1
Temp12 = Temp11+1
Temp13 = Temp12+1
Temp14 = Temp13+1
Temp15 = Temp14+1
Temp16 = Temp15+1


GAMESTART:
	ROM_CALL(CLEARLCD)
	
	res 1, (IY+05)                  ; print 6 rows of menu style.
	res 3, (IY+05)                  ; write over current screen.    
	res 1, (IY+0D)                  ; don't alter text memory.
	
        ld hl, $8C40                    ; tell zshell to recalc checksum
        set 0, (hl)                     ; upon exit.

	; first thing to do, see if we have a saved level
	
	ld hl, (PROGRAM_ADDR)
	ld de, GameSaved
	add hl, de
	ld a, (hl)
	cp 0
	JUMP_NZ(REPLACE_GAME)

	; second thing to do, draw title strings in menu style
	
	ld hl, $0400                    
	ld ($800C), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_1
	add hl, de
	ROM_CALL(D_ZT_STR)              ; display "Columns  v3.0"

	ld hl, $0102                    
	ld ($800C), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_2
	add hl, de
	ROM_CALL(D_ZT_STR)

	ld hl, $1C13                    
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_3
	add hl, de
	ROM_CALL(D_ZM_STR)

	ld hl, $261A                    
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_4
	add hl, de
	ROM_CALL(D_ZM_STR)

	ld hl, $3820                    ; y=54 x=32 
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_10
	add hl, de
	ROM_CALL(D_ZM_STR)
	
	ld a, 4                         ; set initial difficulty to "Easy".
	ld (Blocknum), a                ; Easy=4, Medium=5, Hard=6, etc.
					  
	ld a, 1                         ; set initial block types used for 
	ld (TopTemp), a                 ; RANDINC.
	ld (MidTemp), a
	ld (BottomTemp), a
	
	JUMP_(TITLEBLOCKS_4)            

KEYLOOP_A:
	call GET_KEY
	ld (Temp1), a
	CALL_(RANDINC)                  ; this becomes the random seed generator.
	ld a, (Temp1)
	cp 0
	jr z, KEYLOOP_A                 ; go back if no key pressed (F register 
					; saved in RANDINC.
	cp $37                          ; Exit pressed?
	ret z                           ; yes, exit to zshell.
	cp $03                          ; Right pressed?
	JUMP_Z(PLUS_PRESSED)            ; yes.
	cp $02                          ; Left pressed?
	JUMP_Z(MINUS_PRESSED)           ; yes.
	cp $36                          ; 2nd key pressed?
        JUMP_Z(INSTRUCTIONS)            ; yes.
	jr KEYLOOP_A                    ; invalid key, go back.

PLUS_PRESSED:
	ld a, (Blocknum)
	inc a
	cp 9                            ; Blocknum too big?
	jr z, PLUS_B                    ; yes.
	ld (Blocknum), a                
	JUMP_(DRAWTITLEBLOCKS) 
PLUS_B:
	ld a, 4
	ld (Blocknum), a
	JUMP_(DRAWTITLEBLOCKS)

MINUS_PRESSED:
	ld a, (Blocknum)
	dec a
	cp 3                            ; Blocknum too small?
	jr z, MINUS_B                   ; yes.
	ld (Blocknum), a                
	JUMP_(DRAWTITLEBLOCKS)    
MINUS_B:
	ld a, 8
	ld (Blocknum), a
	JUMP_(DRAWTITLEBLOCKS)    
	
DRAWTITLEBLOCKS:
	ld a, (Blocknum)
	cp 4
	JUMP_Z(TITLEBLOCKS_4)
	cp 5
	JUMP_Z(TITLEBLOCKS_5)
	cp 6
	JUMP_Z(TITLEBLOCKS_6)
	cp 7
	JUMP_Z(TITLEBLOCKS_7)
	cp 8
	JUMP_Z(TITLEBLOCKS_8)
	
TITLEBLOCKS_4:
	; now print "Easy  "
	ld hl, $2F2D                    
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_5
	add hl, de
	ROM_CALL(D_ZM_STR)
	JUMP_(KEYLOOP_A)

TITLEBLOCKS_5:
	; now print "Medium"
	ld hl, $2F2D                    
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_6
	add hl, de
	ROM_CALL(D_ZM_STR)
	JUMP_(KEYLOOP_A) 

TITLEBLOCKS_6:
	; now print "Hard"
	ld hl, $2F2D                    ; y=44, x=80
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_7
	add hl, de
	ROM_CALL(D_ZM_STR)
	JUMP_(KEYLOOP_A)  

TITLEBLOCKS_7:
	; now print "Very Hard"
	ld hl, $2F2D                   ; y=44, x=80
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_8
	add hl, de
	ROM_CALL(D_ZM_STR)
	JUMP_(KEYLOOP_A)  

TITLEBLOCKS_8:
	; now print "Impossible"
	ld hl, $2F2D                    ; y=44, x=80
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_9
	add hl, de
	ROM_CALL(D_ZM_STR)
	JUMP_(KEYLOOP_A)  

INSTRUCTIONS:
	ROM_CALL(CLEARLCD)
	ld de, $000A
	ld ($8333), de
	ld hl, (PROGRAM_ADDR)
	ld de, TeacherStr
	add hl, de
	ROM_CALL(D_ZM_STR)
	
	ld de, $0709
	ld ($8333), de
	ROM_CALL(D_ZM_STR) 
	
	ld de, $0E17
	ld ($8333), de
	ROM_CALL(D_ZM_STR) 
	
	ld de, $1505
	ld ($8333), de
	ROM_CALL(D_ZM_STR) 
	
	ld de, $1C05
	ld ($8333), de
	ROM_CALL(D_ZM_STR) 
	
	ld de, $2305
	ld ($8333), de
	ROM_CALL(D_ZM_STR) 
	
	ld de, $2A05
	ld ($8333), de
	ROM_CALL(D_ZM_STR) 
	
	ld de, $3105
	ld ($8333), de
	ROM_CALL(D_ZM_STR) 
	
	ld de, $3805
	ld ($8333), de
	ROM_CALL(D_ZM_STR) 

	ld hl, $381E                     
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_10
	add hl, de
	ROM_CALL(D_ZM_STR)

PAUSE_2:
	call GET_KEY
	cp 0
	jr z, PAUSE_2
	cp $36
	JUMP_Z(DRAWSCREEN)              ; 2nd pressed, Start Game
	cp $37                          ; exit pressed
	ret z
        jr PAUSE_2                      ; invalid key

DRAWSCREEN:                             ; draws initial playfield
	ROM_CALL(CLEARLCD)
	ld hl, $3A01                    ; y=58 x=01
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Screen_1
	add hl, de
	ROM_CALL(D_ZM_STR)
	
	ld hl, $3A40                    ; y=58 x=64
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Screen_2
	add hl, de
	ROM_CALL(D_ZM_STR)

	ld a, 0
	ld (SuperTemp), a
	ld hl, $0000
	ld (BlocksTotal), hl            ; initialize BlocksTotal.
	ld a,1
	ld (LevelCurrent), a            ; initialize LevelCurrent.
	CALL_(UPDATE_SCORE)
	CALL_(UPDATE_LEVEL)             ; print level and score on screen
	JUMP_(MAIN)

RANDINC:                                ; random function subroutine.
	ld a, (Blocknum)                ; this works on the fact 
	inc a                           ; that the computer is so fast
	ld b, a                         ; that by the time you press a key
	ld a, (TopTemp)                 ; to move, it can increment 3 variables
	inc a                           ; hundreds of times.  These 3 variables
	cp b                            ; become the random blocks generated!
	jr z, RANDINC_1                
	ld (TopTemp), a
	ret
RANDINC_1:
	ld a, 1
	ld (TopTemp), a
	ld a, (MidTemp)
	inc a
	cp b
	jr z, RANDINC_2
	ld (MidTemp), a
	ret
RANDINC_2:
	ld a, 1
	ld (MidTemp), a
	ld a, (BottomTemp)
	inc a
	cp b
	jr z, RANDINC_3
	ld (BottomTemp), a
	ret
RANDINC_3:
	ld a, 1
	ld (BottomTemp), a
	ret

UPDATE_SCORE:
	ld hl, (BlocksTotal)
	ld de, Score1+4
	ld b, 5
SCORELOOP:
	call UNPACK_HL
	add a, '0'                      
	ld (de), a                      
	dec de
	djnz SCORELOOP
	
	ld hl, $3A1E
	ld ($8333), hl
	ld hl, Score1
	ld b, 5
	ROM_CALL(D_LM_STR)
	ret

UPDATE_LEVEL:
	ld a, (LevelCurrent)
	ld hl, $0000
	ld l, a
	ld de, LevelString
	call UNPACK_HL
	add a, '0'
	ld (de), a
	
	ld hl, $3A5A                    ; y=58, x=90
	ld ($8333), hl
	ld hl, LevelString
	ld b, 1                         ; 1 character string...
	ROM_CALL(D_LM_STR)
	ret

;  Now start to play the game!

MAIN:                                   ; This is called after blocks are placed
	ld hl, $811C                    ; Address of block (14,4)
	ld a, (hl)
	cp 0
	JUMP_NZ(LOSEGAME)               ; we can't have a block there!
	CALL_(UPDATE_SCORE)
	CALL_(UPDATE_LEVEL)
	CALL_(CALCDELAY)
	ld (DelayTemp), de
	
	ld a, r
	cp 10
	JUMP_Z(SUPERBLOCK)
	cp 80
	JUMP_Z(SUPERBLOCK)
	cp 130
	JUMP_Z(SUPERBLOCK)
	cp 190
	JUMP_Z(SUPERBLOCK)
	cp 240
	JUMP_Z(SUPERBLOCK)

	ld a, (TopTemp)                 ; load mem with initial block
	ld (TopType), a
	ld a, (MidTemp)
	ld (MidType), a
	ld a, (BottomTemp)
	ld (BottomType), a
	
MAIN_2:
	ld hl, $0E04                    ; x=14, y=4
	ld (Ypos), hl                   ; load initial block position
	CALL_(REDRAW_CURRENT)
	JUMP_(KEYLOOP_B)

SUPERBLOCK:
	ld a, 9
	ld (TopType), a
	ld (MidType), a
	ld (BottomType), a
	ld a, 1
	ld (SuperTemp), a
	JUMP_(MAIN_2)

; redraws the current 3 blocks on the screen
REDRAW_CURRENT:                         ; hl must equal bottom block position
	ld a, (BottomType)
	CALL_(DRAWBLOCK)
	ld a, (MidType)
	inc h
	CALL_(DRAWBLOCK)
	ld a, (TopType)
	inc h
	CALL_(DRAWBLOCK)
	ret

KEYLOOP_B:
	call GET_KEY
	ld (Temp1), a
	ld de, (DelayTemp)
	dec de
	ld (DelayTemp), de
	ld hl, $0000
	call CP_HL_DE
	JUMP_Z(MOVEDOWN)
	CALL_(RANDINC)
	ld a, (Temp1)
	cp 0
	JUMP_Z(KEYLOOP_B)

	cp $02                            ; down key pressed (actually left key!)
	JUMP_Z(MOVEDOWN) 
	cp $04
	JUMP_Z(MOVELEFT)
	cp $01
	JUMP_Z(MOVERIGHT)
	cp $36
	JUMP_Z(FLIPBLOCK)               ; 2nd key pressed
	cp $38
	JUMP_Z(PAUSE)                   ; More key pressed
	cp $37
	ret z                           ; Exit key pressed, go to zshell
	cp $09
	JUMP_Z(SAVEGAME)
	JUMP_(KEYLOOP_B)

PAUSE:
	call GET_KEY
	cp 0
	jr z, PAUSE
	cp $38
	JUMP_Z(KEYLOOP_B)               ; more pressed, return
	jr PAUSE                        ; invalid key

CALCDELAY:                              ; loads de with a delay value, depending
					; on current level.
	ld a, (LevelCurrent)
	ld bc, DelayString
	ld hl, (PROGRAM_ADDR)
	add hl, bc
CALCLOOP:
	dec a
	inc hl
	inc hl
	cp 0
	jr z, PUT_DELAY
	jr CALCLOOP
PUT_DELAY:
	ld e, (hl)
	inc hl
	ld d, (hl)                      ; remember, there is no --ld de, (hl)--
	ret

MOVEDOWN:
	ld hl, (Ypos)
	dec h
	ld a, h
	cp 0                            ; are we at the bottom?
	JUMP_Z(PLACE_BLOCKS)            ; yes

	ld (Temp5), hl
	CALL_(GET_TYPE)                 ; returns block type in a at current hl
	ld hl, (Temp5)
	cp 0                            ; block already there?
	JUMP_NZ(PLACE_BLOCKS)           ; yes
	
	ld (Ypos), hl
	ld a, 0
	inc h
	inc h
	inc h
	CALL_(DRAWBLOCK)                ; we can move down, so delete top block.
	
	ld hl, (Ypos)                   ; replace original coordinates.
	CALL_(REDRAW_CURRENT)
	CALL_(CALCDELAY)                ; reset delay
	ld (DelayTemp), de
	JUMP_Z(KEYLOOP_B)               ; all done!

MOVELEFT:
	ld hl, (Ypos)
	dec l
	ld a, l
	cp 0                            ; are we too far left?
	JUMP_Z(KEYLOOP_B)               ; yes

	ld (Temp5), hl
	CALL_(GET_TYPE)                 ; returns block type in a at current hl
	ld hl, (Temp5)
	cp 0                            ; block already there?
	JUMP_NZ(KEYLOOP_B)              ; yes

	ld (Ypos), hl                   ; delete blocks on screen and move left!
	ld a, 0
	inc l
	CALL_(DRAWBLOCK)
	inc h
	CALL_(DRAWBLOCK)
	inc h
	CALL_(DRAWBLOCK)
	ld hl, (Ypos)
	CALL_(REDRAW_CURRENT)
	JUMP_Z(KEYLOOP_B)

MOVERIGHT:
	ld hl, (Ypos)
	inc l
	ld a, l
	cp 8                            ; are we too far right?
	JUMP_Z(KEYLOOP_B)               ; yes

	ld (Temp5), hl
	CALL_(GET_TYPE)                 ; returns block type in a at current hl
	ld hl, (Temp5)
	cp 0                            ; block already there?
	JUMP_NZ(KEYLOOP_B)              ; yes

	ld (Ypos), hl                   ; delete blocks on screen and move right!
	ld a, 0
	dec l
	CALL_(DRAWBLOCK)
	inc h
	CALL_(DRAWBLOCK)
	inc h
	CALL_(DRAWBLOCK)
	ld hl, (Ypos)
	CALL_(REDRAW_CURRENT)
	JUMP_(KEYLOOP_B)

FLIPBLOCK:
	ld a, (BottomType)              ; Flip around blocks
	ld d, a
	ld a, (MidType) 
	ld (BottomType), a
	ld a, (TopType)
	ld (MidType), a
	ld a, d
	ld (TopType), a
	
	CALL_(REDRAW_CURRENT)
	JUMP_(KEYLOOP_B)

;  given a block address in hl (such as "(14,4)"), this returns the type and
;  actual address of the block in a and hl, respectively.
GET_TYPE:
	ld (Temp1), hl
	ld a, l
	ld hl, $80CE                    ; start of variables minus 17
	ld bc, $0010                    ; bc = 16
GET_TYPE_LOOP:
	add hl, bc                      ; first find the column address
	dec a
	cp 0
	jr nz, GET_TYPE_LOOP

	ld (Temp3), hl                  ; now find column + row
	ld hl, (Temp1)
	ld b, 0
	ld c, h
	ld hl, (Temp3)
	add hl, bc
	ld a, (hl)                      ; hl=block address, a=block type
	ret

;  After a block hits the bottom or hits another block, this routine
;  loads it into the block memory for use in BLOCKCHECK.
PLACE_BLOCKS:
	ld a, (SuperTemp)
	cp 1
	JUMP_Z(SUPERBLOCK_2)            ; do we have a superblock?
	
	ld hl, (Ypos)
	CALL_(GET_TYPE)
	ld a, (BottomType)
	ld (hl), a
	inc hl
	ld a, (MidType)
	ld (hl), a
	inc hl
	ld a, (TopType)
	ld (hl), a
	JUMP_(SHOWBLOCKS)

SUPERBLOCK_2:
	ld a, 0
	ld (SuperTemp), a
	
	ld hl, (Ypos)
	dec h
	JUMP_Z(SUPERBLOCK_5)
	CALL_(GET_TYPE)
	ld b, 112                       ; 112 blocks in memory
	ld hl, $80DF

SUPERBLOCK_3:        
	ld c, (hl)
	cp c
	jr z, SUPERBLOCK_4
	inc hl
	djnz SUPERBLOCK_3
	JUMP_(SHOWDELETED)

SUPERBLOCK_4:
	set 7, c
	ld (hl), c
	inc hl
	djnz SUPERBLOCK_3
	JUMP_(SHOWDELETED)

SUPERBLOCK_5:
	inc h
	ld a, 0
	CALL_(DRAWBLOCK)
	inc h
	CALL_(DRAWBLOCK)
	inc h
	CALL_(DRAWBLOCK)
	JUMP_(MAIN)

SUPERBLOCK_6:

; NOTICE:  For some reason, I mixed up references to "east" and "west" in 
; the next routine.  So when it says, checking "northeast", it's really 
; checking "northwest."  However, the algorhythm works fine, and you don't 
; have to change it.


; this routine checks to see if we have 3 blocks in a row anywhere.
BLOCKCHECK:
	ld de, $0101                    ; de is the x,y block pointer
	ld hl, $80DF                    ; hl points to the (first) block mem address
CHECKLOOP:
	ld a, (hl)
	
	ld (Temp1), de                  ; re-initialize de and hl with
	ld (Temp3), hl                  ; new block positions
	
	ld b, a                         ; no block in address, go to 
	cp 0                            ; next column
	JUMP_Z(NEXTCOL)

	res 7, b                        ; get b ready for comparison


N:                                      ; check for match in northern direction
	ld c, 1                         ; initialize counter
	inc hl
	inc d
	ld a, 17
	cp d                            ; too high?
	JUMP_Z(W)                       ; yes.

	ld a, (hl)                      ; begin check
	res 7, a
	cp b                            ; are the blocks the same?
	jr z, N_2                       ; yes.
	JUMP_(W)                        ; no.
N_2:
	inc c
	inc hl
	inc d
	ld a, 17
	cp d                            ; too high?
	jr z, N_3                       ; yes.
	ld a, (hl)
	res 7, a
	cp b                            ; are the blocks the same?
	jr z, N_2                       ; yes, check next block
N_3:
	ld a, 2
	cp c                            ; did we have 3 blocks in a row?
	JUMP_Z(W)                         ; no.
N_4:
	dec hl
	set 7, (hl)                     ; tag all of the matching blocks
	dec c
	jr nz, (N_4)
	

W:                                      ; check west
	ld c, 1                         ; initialize counter
	
	ld de, (Temp1)                  ; reset coordinates
	ld hl, (Temp3)
	
	push de
	ld de, $0010
	add hl, de
	pop de
	inc e
	ld a, 8
	cp e
	JUMP_Z(NE)                      ; jump if too far west

	ld a, (hl)                      ; begin check
	res 7, a
	cp b                            ; are the blocks the same?
	jr z, W_2                       ; yes.
	JUMP_(NE)                       ; no.
W_2:
	inc c
	push de
	ld de, $0010
	add hl, de
	pop de
	inc e
	ld a, 8
	cp e
	jr z, W_3                       ; jump if too far west
	ld a, (hl)
	res 7, a
	cp b                            ; are the blocks the same?
	jr z, W_2                       ; yes, check next block
W_3:
	ld a, 2
	cp c                            ; did we have 3 blocks in a row?
	JUMP_Z(NE)                      ; no.

	scf
	ccf
	ld de, $0010
W_4:
	sbc hl, de
	set 7, (hl)                     ; tag all of the matching blocks
	dec c
	jr nz, (W_4)
	

NE:                                     ; check northeast
	ld c, 1                         ; initialize counter
	
	ld de, (Temp1)                  ; reset coordinates
	ld hl, (Temp3)
	
	push de
	ld de, $000F
	scf
	ccf
	sbc hl, de
	pop de
	inc d
	ld a, 17
	cp d
	JUMP_Z(NW)                      ; jump if too high
	dec e
	JUMP_Z(NW)                      ; jump if too far east

	ld a, (hl)                      ; begin check
	res 7, a
	cp b                            ; are the blocks the same?
	jr z, NE_2                      ; yes.
	JUMP_(NW)                       ; no.
NE_2:
	inc c
	push de
	ld de, $000F
	scf
	ccf
	sbc hl, de
	pop de
	inc d
	ld a, 17
	cp d
	jr z, NE_3                      ; jump if too high
	dec e
	jr z, NE_3                      ; jump if too far east

	ld a, (hl)                      ; begin check
	res 7, a
	cp b                            ; are the blocks the same?
	jr z, NE_2                      ; yes.
NE_3:
	ld a, 2
	cp c                            ; did we have 3 blocks in a row?
	JUMP_Z(NW)                      ; no.

	ld de, $000F
NE_4:
	add hl, de
	set 7, (hl)                     ; tag all of the matching blocks
	dec c
	jr nz, (NE_4)
	

NW:                                     ; check northwest
	ld c, 1                         ; initialize counter
	
	ld de, (Temp1)                  ; reset coordinates
	ld hl, (Temp3)
	
	push de
	ld de, $0011
	add hl, de
	pop de
	inc d
	ld a, 17
	cp d
	JUMP_Z(NEXTBLOCK)               ; jump if too high
	inc e
	ld a, 8
	cp e
	JUMP_Z(NEXTBLOCK)               ; jump if too far west

	ld a, (hl)                      ; begin check
	res 7, a
	cp b                            ; are the blocks the same?
	jr z, NW_2                      ; yes.
	JUMP_(NEXTBLOCK)                ; no.
NW_2:
	inc c
	push de
	ld de, $0011
	add hl, de
	pop de
	inc d
	ld a, 17
	cp d
	jr z, NW_3                      ; jump if too high
	inc e
	ld a, 8
	cp e
	jr z, NW_3                      ; jump if too far west

	ld a, (hl)                      ; begin check
	res 7, a
	cp b                            ; are the blocks the same?
	jr z, NW_2                      ; yes.
NW_3:
	ld a, 2
	cp c                            ; did we have 3 blocks in a row?
	JUMP_Z(NEXTBLOCK)               ; no.

	scf
	ccf
	ld de, $0011
NW_4:
	sbc hl, de
	set 7, (hl)                     ; tag all of the matching blocks
	dec c
	jr nz, (NW_4)
	

NEXTBLOCK:
	ld de, (Temp1)                  ; reset coordinates and start checking
	ld hl, (Temp3)                  ; again!
	inc hl
	inc d
	ld a, 17
	cp d
	JUMP_Z(NEXTCOL)
	JUMP_(CHECKLOOP)
NEXTCOL:
	ld d, 1
	inc e
	ld (Temp1), de
	ld a, 8
	cp e
	JUMP_Z(SHOWDELETED)             ; all done checking!
	ld h, d
	ld l, e
	CALL_(GET_TYPE)                 ; finds hl address of next column
	ld de, (Temp1)
	JUMP_(CHECKLOOP)                ; go back and start over.


; This function deletes matching blocks on the screen, after a delay.
; This gives the effect of them "disappearing", and then being pushed 
; back down in DROPBLOCKS.
SHOWDELETED:
	ld hl, (BlocksTotal)
	ld (BlocksTotalTemp), hl        ; save BlocksTotal for later comparison
	
	; now let's delay a while...
	ld b, $FF
	ld a, $FF
SHOW_1:
	dec b
	jr nz, SHOW_1
	dec a
	jr nz, SHOW_1
	; all done delaying

	ld hl, $80DF
	ld de, $0101                    ; load hl and de with starting coordinates
SHOW_2:
	ld a, (hl)
	bit 7, a
	jr nz, SHOW_3
	inc hl
	inc d
	ld a, 17
	cp d
	JUMP_Z(SHOW_4)
	jr SHOW_2
SHOW_3:
	ld a, 0
	ld (Temp1), hl
	ld h, d
	ld l, e
	CALL_(DRAWBLOCK)
	ld hl, (BlocksTotal)
	inc hl
	ld (BlocksTotal), hl            ; increment and save score
	ld (Temp3), de
	CALL_(LEVELINC)                 ; increment level if needed.
	ld hl, (Temp1)
	ld de, (Temp3)
	inc hl
	inc d
	ld a, 17
	cp d                            ; too high?
	jr z, SHOW_4                    ; yep, increment column
	JUMP_(SHOW_2)
SHOW_4:
	ld d, 1
	inc e
	ld a, 8
	cp e                            ; are we all done?
	JUMP_Z(DROPBLOCKS)              ; yes.
	JUMP_(SHOW_2)                   ; no.

LEVELINC:                               ; subroutine increments level
	ld hl, (BlocksTotal)
	ld a, l                         
	res 7, a
	cp 127                          
	ret nz                          
	
	ld a, (LevelCurrent)
	inc a
	ld b, a
	ld a, 10                        
	cp b                            ; are we already at level 9?
	ret z                           ; yes.
	ld a, b                         ; no.
	ld (LevelCurrent), a
	ret

;  moves blocks down after matching blocks were erased.
DROPBLOCKS:
	ld hl, (BlocksTotal)
	ld de, (BlocksTotalTemp)
	call CP_HL_DE                   ; were there any matching blocks?
	JUMP_Z(MAIN)                    ; nope!  Start all over!

	; now let's delay a while...
	ld b, $FF
	ld a, $FF
DROPBLOCKS_1:
	dec b
	jr nz, DROPBLOCKS_1
	dec a
	jr nz, DROPBLOCKS_1
	; all done delaying

	ld hl, $80DF
	ld (Temp1), hl
	ld de, $0101
	ld (Temp3), de                  ; initialize coordinates in de and hl
DROPBLOCKS_2:
	ld hl, (Temp1)
	ld de, (Temp3)                  ; reset back to original coordinates
	
	ld a, (hl)
	bit 7, a                        ; does this block need to be deleted?
	jr nz, DROPBLOCKS_3             ; yes.
	inc hl                          ; no, go to next byte
	ld (Temp1), hl
	inc d
	ld (Temp3), de
	ld a, 17
	cp d
	JUMP_Z(DROPBLOCKS_4)
	jr DROPBLOCKS_2
DROPBLOCKS_3:                           ; this routine moves all the blocks down
	inc hl                                 
	inc d
	ld a, 17
	cp d                            ; are we too high?
	JUMP_Z(DROPBLOCKS_5)            ; yep.
	ld a, (hl)                      ; now drop each block down, one at a time
	dec hl
	ld (hl), a
	inc hl                          
	jr DROPBLOCKS_3                 ; go to next block to drop
DROPBLOCKS_4:   
	ld d, 1
	inc e                           ; go to next column
	ld (Temp3), de                  ; reset x,y position
	ld a, 8
	cp e                            ; are we already in column 7?
	JUMP_Z(SHOWBLOCKS)              ; yes
	JUMP_(DROPBLOCKS_2)             ; no
DROPBLOCKS_5:
	dec hl
	ld a, 0
	ld (hl), a                      ; were at the top, so put a 0 in block 16,y
	JUMP_(DROPBLOCKS_2)             ; now start over

;  This routine completely redraws the blocks in memory.
SHOWBLOCKS:
	ld hl, $80DF                    ; starting block minus 1
	ld de, $0101
SHOWBLOCKS_1: 
	ld a, (hl)                      ; load block type into a
	push hl
	ld h, d                         ; load de into hl (for DRAWBLOCK)
	ld l, e                         
	CALL_(DRAWBLOCK)
	pop hl
	inc hl
	inc d
	ld a, 17
	cp d
	jr z, SHOWBLOCKS_2
	jr SHOWBLOCKS_1
SHOWBLOCKS_2:
	ld d, 1
	inc e
	ld a, 8
	cp e                            ; are we already in column 7?
	JUMP_Z(BLOCKCHECK)              ; YES!!  Start over and recheck for 
					; new block matches.
	JUMP_(SHOWBLOCKS_1)


;  This vital subroutine draws a block depending on its type and position.
DRAWBLOCK:                               
	ld (Temp7), hl                  ; a must contain block type, hl 
	ld (Temp9), de                  ; contains position
	ld (Temp11), bc
	ld (Temp13), a
	; first find row...
	ld de, $FBFF                    ; Video mem minus 1
	ld l, h
	ld h, 0
	add hl, de
	ld b, h
	ld c, l
	; then find column...
	ld hl, (Temp7)
	ld a, l
	ld de, 128
	ld h, b
	ld l, c
DRAWBLOCK_A:
	dec a
	jr z, DRAWBLOCK_B
	add hl, de
	jr DRAWBLOCK_A
DRAWBLOCK_B:                            ; hl now contains first pixel address
	ld a, (Temp13)
	cp 0
	JUMP_Z(DRAW_0)
	cp 1
	JUMP_Z(DRAW_1)
	cp 2
	JUMP_Z(DRAW_2)
	cp 3
	JUMP_Z(DRAW_3)
	cp 4
	JUMP_Z(DRAW_4)
	cp 5
	JUMP_Z(DRAW_5)
	cp 6
	JUMP_Z(DRAW_6)
	cp 7
	JUMP_Z(DRAW_7)
	cp 8
	JUMP_Z(DRAW_8)
	cp 9
	JUMP_Z(DRAW_9)
DRAW_0:                                 
	ld a, 00000000b
	ld (hl), a
	ld de, 16
	add hl, de
	ld (hl), a
	add hl, de
	ld (hl), a
	add hl, de
	ld (hl), a
	add hl, de
	ld (hl), a
	add hl, de
	ld (hl), a
	add hl, de
	ld (hl), a
	add hl, de
	ld (hl), a
	JUMP_(DRAWEND)                  
DRAW_1:                               
	ld a, 00000000b                 
	ld (hl), a
	ld de, 16                       ;  I could have done this using
	add hl, de                      ;  some sort of array in which you
	ld a, 01111111b                 ;  increment hl to find the next
	ld (hl), a                      ;  block line (depending on its type),
	add hl, de                      ;  but (a) when I tried it it didn't
	ld a, 01000001b                 ;  work and (b) this is faster.
	ld (hl), a
	add hl, de
	ld a, 01000001b
	ld (hl), a
	add hl, de
	ld a, 01000001b
	ld (hl), a
	add hl, de
	ld a, 01000001b
	ld (hl), a
	add hl, de
	ld a, 01000001b
	ld (hl), a
	add hl, de
	ld a, 01111111b
	ld (hl), a
	JUMP_(DRAWEND)
DRAW_2:
	ld a, 00000000b
	ld (hl), a
	ld de, 16
	add hl, de
	ld a, 01111111b
	ld (hl), a
	add hl, de
	ld a, 01111111b
	ld (hl), a
	add hl, de
	ld a, 01111111b
	ld (hl), a
	add hl, de
	ld a, 01111111b
	ld (hl), a
	add hl, de
	ld a, 01111111b
	ld (hl), a
	add hl, de
	ld a, 01111111b
	ld (hl), a
	add hl, de
	ld a, 01111111b
	ld (hl), a
	JUMP_(DRAWEND)
DRAW_3:
	ld a, 00000000b
	ld (hl), a
	ld de, 16
	add hl, de
	ld a, 00001000b
	ld (hl), a
	add hl, de
	ld a, 00011100b
	ld (hl), a
	add hl, de
	ld a, 00111110b
	ld (hl), a
	add hl, de
	ld a, 01111111b
	ld (hl), a
	add hl, de
	ld a, 00111110b
	ld (hl), a
	add hl, de
	ld a, 00011100b
	ld (hl), a
	add hl, de
	ld a, 00001000b
	ld (hl), a
	JUMP_(DRAWEND)
DRAW_4:
	ld a, 00000000b
	ld (hl), a
	ld de, 16
	add hl, de
	ld a, 01100011b
	ld (hl), a
	add hl, de
	ld a, 01100011b
	ld (hl), a
	add hl, de
	ld a, 00010100b
	ld (hl), a
	add hl, de
	ld a, 00001000b
	ld (hl), a
	add hl, de
	ld a, 00010100b
	ld (hl), a
	add hl, de
	ld a, 01100011b
	ld (hl), a
	add hl, de
	ld a, 01100011b
	ld (hl), a
	JUMP_(DRAWEND)

DRAW_5:
	ld a, 00000000b
	ld (hl), a
	ld de, 16
	add hl, de
	ld a, 01010101b
	ld (hl), a
	add hl, de
	ld a, 00101010b
	ld (hl), a
	add hl, de
	ld a, 01010101b
	ld (hl), a
	add hl, de
	ld a, 00101010b
	ld (hl), a
	add hl, de
	ld a, 01010101b
	ld (hl), a
	add hl, de
	ld a, 00101010b
	ld (hl), a
	add hl, de
	ld a, 01010101b
	ld (hl), a
	JUMP_(DRAWEND)
DRAW_6:
	ld a, 00000000b
	ld (hl), a
	ld de, 16
	add hl, de
	ld a, 01111111b
	ld (hl), a
	add hl, de
	ld a, 01001001b
	ld (hl), a
	add hl, de
	ld a, 01001001b
	ld (hl), a
	add hl, de
	ld a, 01111111b
	ld (hl), a
	add hl, de
	ld a, 01001001b
	ld (hl), a
	add hl, de
	ld a, 01001001b
	ld (hl), a
	add hl, de
	ld a, 01111111b
	ld (hl), a
	JUMP_(DRAWEND)

DRAW_7:
	ld a, 00000000b
	ld (hl), a
	ld de, 16
	add hl, de
	ld a, 00001000b
	ld (hl), a
	add hl, de
	ld a, 00010100b
	ld (hl), a
	add hl, de
	ld a, 00100010b
	ld (hl), a
	add hl, de
	ld a, 01000001b
	ld (hl), a
	add hl, de
	ld a, 00100010b
	ld (hl), a
	add hl, de
	ld a, 00010100b
	ld (hl), a
	add hl, de
	ld a, 00001000b
	ld (hl), a
	JUMP_(DRAWEND)

DRAW_8:
	ld a, 00000000b
	ld (hl), a
	ld de, 16
	add hl, de
	ld a, 01111111b
	ld (hl), a
	add hl, de
	ld a, 00111110b
	ld (hl), a
	add hl, de
	ld a, 00011100b
	ld (hl), a
	add hl, de
	ld a, 00001000b
	ld (hl), a
	add hl, de
	ld a, 00011100b
	ld (hl), a
	add hl, de
	ld a, 00111110b
	ld (hl), a
	add hl, de
	ld a, 01111111b
	ld (hl), a
	JUMP_(DRAWEND)

DRAW_9:
	ld a, 00000000b
	ld (hl), a
	ld de, 16
	add hl, de
	ld a, 01000001b
	ld (hl), a
	add hl, de
	ld a, 01100001b
	ld (hl), a
	add hl, de
	ld a, 01010001b
	ld (hl), a
	add hl, de
	ld a, 01001001b
	ld (hl), a
	add hl, de
	ld a, 01000101b
	ld (hl), a
	add hl, de
	ld a, 01000011b
	ld (hl), a
	add hl, de
	ld a, 01000001b
	ld (hl), a
	JUMP_(DRAWEND)

DRAWEND:
	ld hl, (Temp7)
	ld de, (Temp9)
	ld bc, (Temp11)
	ld a, (Temp13)
	ret

LOSEGAME:
	ROM_CALL(CLEARLCD)
	ld a, (Blocknum)
	cp 4
	JUMP_Z(LOSEEASY)
	cp 5
	JUMP_Z(LOSEMED)
	cp 6
	JUMP_Z(LOSEHARD)
	cp 7
	JUMP_Z(LOSEVHARD)
	JUMP_(LOSEIMP)
LOSEEASY:
	ld de, (PROGRAM_ADDR)
	ld hl, EasyScore+3
	add hl, de
	call LD_HL_MHL
	ld de, (BlocksTotal)
	scf
	ccf
	sbc hl, de
	JUMP_C(LOSEEASY_2)
	JUMP_(GAMEOVER)
LOSEEASY_2:
	CALL_(INPUT_INITIALS)
	ld bc, 3
	ld de, (PROGRAM_ADDR)
	ld hl, EasyScore
	add hl, de
	ld d, h
	ld e, l
	ld hl, Initial1 
	ldir
	
	ld de, (PROGRAM_ADDR)
	ld hl, EasyScore+3
	add hl, de
	ld de, (BlocksTotal)
	ld (hl), e
	inc hl
	ld (hl), d

	ld a, (Blocknum)
	inc hl
	ld (hl), a
	JUMP_(GAMEOVER)

LOSEMED:
	ld de, (PROGRAM_ADDR)
	ld hl, MedScore+3
	add hl, de
	call LD_HL_MHL
	ld de, (BlocksTotal)
	scf
	ccf
	sbc hl, de
	JUMP_C(LOSEMED_2)
	JUMP_(GAMEOVER)
LOSEMED_2:
	CALL_(INPUT_INITIALS)
	ld bc, 3
	ld de, (PROGRAM_ADDR)
	ld hl, MedScore
	add hl, de
	ld d, h
	ld e, l
	ld hl, Initial1 
	ldir
	
	ld de, (PROGRAM_ADDR)
	ld hl, MedScore+3
	add hl, de
	ld de, (BlocksTotal)
	ld (hl), e
	inc hl
	ld (hl), d

	ld a, (Blocknum)
	inc hl
	ld (hl), a
	JUMP_(GAMEOVER)

LOSEHARD:
	ld de, (PROGRAM_ADDR)
	ld hl, HardScore+3
	add hl, de
	call LD_HL_MHL
	ld de, (BlocksTotal)
	scf
	ccf
	sbc hl, de
	JUMP_C(LOSEHARD_2)
	JUMP_(GAMEOVER)
LOSEHARD_2:
	CALL_(INPUT_INITIALS)
	ld bc, 3
	ld de, (PROGRAM_ADDR)
	ld hl, HardScore
	add hl, de
	ld d, h
	ld e, l
	ld hl, Initial1 
	ldir
	
	ld de, (PROGRAM_ADDR)
	ld hl, HardScore+3
	add hl, de
	ld de, (BlocksTotal)
	ld (hl), e
	inc hl
	ld (hl), d

	ld a, (Blocknum)
	inc hl
	ld (hl), a
	JUMP_(GAMEOVER)

LOSEVHARD:
	ld de, (PROGRAM_ADDR)
	ld hl, VHardScore+3
	add hl, de
	call LD_HL_MHL
	ld de, (BlocksTotal)
	scf
	ccf
	sbc hl, de
	JUMP_C(LOSEVHARD_2)
	JUMP_(GAMEOVER)
LOSEVHARD_2:
	CALL_(INPUT_INITIALS)
	ld bc, 3
	ld de, (PROGRAM_ADDR)
	ld hl, VHardScore
	add hl, de
	ld d, h
	ld e, l
	ld hl, Initial1 
	ldir
	
	ld de, (PROGRAM_ADDR)
	ld hl, VHardScore+3
	add hl, de
	ld de, (BlocksTotal)
	ld (hl), e
	inc hl
	ld (hl), d

	ld a, (Blocknum)
	inc hl
	ld (hl), a
	JUMP_(GAMEOVER)

LOSEIMP:
	ld de, (PROGRAM_ADDR)
	ld hl, ImpScore+3
	add hl, de
	call LD_HL_MHL
	ld de, (BlocksTotal)
	scf
	ccf
	sbc hl, de
	JUMP_C(LOSEIMP_2)
	JUMP_(GAMEOVER)
LOSEIMP_2:
	CALL_(INPUT_INITIALS)
	ld bc, 3
	ld de, (PROGRAM_ADDR)
	ld hl, ImpScore
	add hl, de
	ld d, h
	ld e, l
	ld hl, Initial1 
	ldir
	
	ld de, (PROGRAM_ADDR)
	ld hl, ImpScore+3
	add hl, de
	ld de, (BlocksTotal)
	ld (hl), e
	inc hl
	ld (hl), d

	ld a, (Blocknum)
	inc hl
	ld (hl), a
	JUMP_(GAMEOVER)

GAMEOVER:
	ROM_CALL(CLEARLCD)
	ld hl, $0028                    
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, GameOver_1
	add hl, de
	ROM_CALL(D_ZM_STR)

	ld hl, $080F                    
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, GameOver_2
	add hl, de
	ROM_CALL(D_ZM_STR)

	ld hl, (BlocksTotal)
	ld de, Score1+4
	ld b, 5
GAMEOVER_2:
	call UNPACK_HL
	add a, '0'                      
	ld (de), a                      
	dec de
	djnz GAMEOVER_2
	
	ld hl, $083F
	ld ($8333), hl
	ld hl, Score1
	ld b, 5
	ROM_CALL(D_LM_STR)
	
	ld a, (Blocknum)
	cp 4
	JUMP_Z(PRINTEASY)
	cp 5
	JUMP_Z(PRINTMED)
	cp 6
	JUMP_Z(PRINTHARD)
	cp 7
	JUMP_Z(PRINTVHARD)
	JUMP_(PRINTIMP)

PRINTEASY:
	ld hl, ($8333)
	inc hl
	inc hl
	inc hl
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_5
	add hl, de
	ROM_CALL(D_ZM_STR)
	JUMP_(GAMEOVER_3)
PRINTMED:
	ld hl, ($8333)
	inc hl
	inc hl
	inc hl
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_6
	add hl, de
	ROM_CALL(D_ZM_STR)
	JUMP_(GAMEOVER_3)
PRINTHARD:
	ld hl, ($8333)
	inc hl
	inc hl
	inc hl
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_7
	add hl, de
	ROM_CALL(D_ZM_STR)
	JUMP_(GAMEOVER_3)
PRINTVHARD:
	ld hl, ($8333)
	inc hl
	inc hl
	inc hl
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_8
	add hl, de
	ROM_CALL(D_ZM_STR)
	JUMP_(GAMEOVER_3)
PRINTIMP:
	ld hl, ($8333)
	inc hl
	inc hl
	inc hl
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Title_9
	add hl, de
	ROM_CALL(D_ZM_STR)
	JUMP_(GAMEOVER_3)

GAMEOVER_3:
	ld hl, $1028
	ld ($8333), hl
	ld hl, GameOver_5
	ld de, (PROGRAM_ADDR)
	add hl, de
	ROM_CALL(D_ZM_STR)

	ld hl, $1820
	ld ($8333), hl
	ld de, (PROGRAM_ADDR)
	ld hl, EasyScore
	add hl, de
	CALL_(PRINTHIGHSCORE)
	
	ld hl, $2020
	ld ($8333), hl
	ld de, (PROGRAM_ADDR)
	ld hl, MedScore
	add hl, de
	CALL_(PRINTHIGHSCORE)
	
	ld hl, $2820
	ld ($8333), hl
	ld de, (PROGRAM_ADDR)
	ld hl, HardScore
	add hl, de
	CALL_(PRINTHIGHSCORE)
	
	ld hl, $3020
	ld ($8333), hl
	ld de, (PROGRAM_ADDR)
	ld hl, VHardScore
	add hl, de
	CALL_(PRINTHIGHSCORE)
	
	ld hl, $3820
	ld ($8333), hl
	ld de, (PROGRAM_ADDR)
	ld hl, ImpScore
	add hl, de
	CALL_(PRINTHIGHSCORE)
	
	JUMP_(WAIT_FOR_KEY)

PRINTHIGHSCORE:
	ld b, 3
	ld (Temp1), hl
	ROM_CALL(D_LM_STR)
	ld hl, ($8333)
	inc l
	inc l
	inc l
	inc l
	ld ($8333), hl
	ld hl, (Temp1)
	inc hl
	inc hl
	inc hl
	ld (Temp1), hl
	call LD_HL_MHL
	
	ld de, Score1+4
	ld b, 5
PRINTHIGHSCORE_2:
	call UNPACK_HL
	add a, '0'                      
	ld (de), a                      
	dec de
	djnz PRINTHIGHSCORE_2
	
	ld hl, Score1
	ld b, 5
	ROM_CALL(D_LM_STR)

	ld hl, ($8333)
	inc l
	inc l
	inc l
	inc l
	ld ($8333), hl

	ld hl, (Temp1)
	inc hl
	inc hl
	ld a, (hl)
	cp 4
	JUMP_Z(PRINTHIGHSCORE_E)
	cp 5
	JUMP_Z(PRINTHIGHSCORE_M)
	cp 6
	JUMP_Z(PRINTHIGHSCORE_H)
	cp 7
	JUMP_Z(PRINTHIGHSCORE_V)
	JUMP_(PRINTHIGHSCORE_I)
PRINTHIGHSCORE_E:
	ld hl, (PROGRAM_ADDR)
	ld de, Title_5
	add hl, de
	ROM_CALL(D_ZM_STR)
	ret
PRINTHIGHSCORE_M:
	ld hl, (PROGRAM_ADDR)
	ld de, Title_6
	add hl, de
	ROM_CALL(D_ZM_STR)
	ret
PRINTHIGHSCORE_H:
	ld hl, (PROGRAM_ADDR)
	ld de, Title_7
	add hl, de
	ROM_CALL(D_ZM_STR)
	ret
PRINTHIGHSCORE_V:
	ld hl, (PROGRAM_ADDR)
	ld de, Title_8
	add hl, de
	ROM_CALL(D_ZM_STR)
	ret
PRINTHIGHSCORE_I:
	ld hl, (PROGRAM_ADDR)
	ld de, Title_9
	add hl, de
	ROM_CALL(D_ZM_STR)
	ret

INPUT_INITIALS:
	ROM_CALL(CLEARLCD)
	ld hl, $0122                    ; y=1, x=34 (adjust)
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, GameOver_3  
	add hl, de
	ROM_CALL(D_ZM_STR)
	
	ld hl, $1E1B                    ; y=30, x=27 (adjust)
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, GameOver_4  
	add hl, de
	ROM_CALL(D_ZM_STR)
	ld hl, $2E35                    ; y=46, x=60
	ld ($8333), hl                  ; this initializes where the 3 initials
					; will be put.
	ld de, Initial1
	ld (Temp3), de
INITIALS_A:
	call GET_KEY
	cp 0
	jr z, INITIALS_A
	ld hl, ASCII_Table-1
	ld de, (PROGRAM_ADDR)
	add hl, de
	ld c, 0
	ld b, a
INITIALS_B:        
	inc hl
	djnz INITIALS_B
	ld a, (hl)
	cp 0
	JUMP_Z(INITIALS_A)
	ld de, (Temp3)
	ld (de), a                      ; load key into InitialX variable
	ROM_CALL(M_CHARPUT)
	ld de, (Temp3)
	inc de
	ld (Temp3), de
	ld hl, Initial3+1
	call CP_HL_DE
	JUMP_NZ(INITIALS_A)
	ret

WAIT_FOR_KEY:
	call GET_KEY
	cp 0
	jr z, WAIT_FOR_KEY
	ret                             ; return to zshell on any keypress



SAVEGAME:
	ld hl, (PROGRAM_ADDR)
	ld de, GameSaved
	add hl, de
	ld a, 1
	ld (hl), a                      ; tell columns that a game is saved
	
	ld hl, (PROGRAM_ADDR)
	ld de, SaveMemory
	add hl, de
	ld d, h
	ld e, l
	ld hl, $80DF
	ld bc, 140                      
	ldir                            ; store about 140 bytes to save game 

	ret                             ; return to zshell.

REPLACE_GAME:
	ld hl, (PROGRAM_ADDR)
	ld de, GameSaved
	add hl, de
	ld a, 0
	ld (hl), a                      ; reset GameSaved
	
	ld hl, SaveMemory
	ld de, (PROGRAM_ADDR)
	add hl, de
	ld de, $80DF
	ld bc, 140
	ldir                            ; replace text memory
REDRAWBLOCKS:
	ld hl, $80DF                    ; starting block minus 1
	ld de, $0101
REDRAWBLOCKS_1: 
	ld a, (hl)                      ; load block type into a
	push hl
	ld h, d                         ; load de into hl (for DRAWBLOCK)
	ld l, e                         
	CALL_(DRAWBLOCK)
	pop hl
	inc hl
	inc d
	ld a, 17
	cp d
	jr z, REDRAWBLOCKS_2
	jr REDRAWBLOCKS_1
REDRAWBLOCKS_2:
	ld d, 1
	inc e
	ld a, 8
	cp e                            ; are we already in column 7?
	JUMP_NZ(REDRAWBLOCKS_1)         ; no, start next column
	
	ld hl, (Ypos)                   ; redraw current blocks
	ld a, (BottomType)
	CALL_(DRAWBLOCK)
	ld a, (MidType)
	inc h
	CALL_(DRAWBLOCK)
	ld a, (TopType)
	inc h
	CALL_(DRAWBLOCK)

	ld hl, $3A01                    ; y=58 x=01
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Screen_1
	add hl, de
	ROM_CALL(D_ZM_STR)
	
	ld hl, $3A40                    ; y=58 x=64
	ld ($8333), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Screen_2
	add hl, de
	ROM_CALL(D_ZM_STR)

	CALL_(UPDATE_SCORE)
	CALL_(UPDATE_LEVEL)             ; print level and score on screen
	
	JUMP_(PAUSE)                    ; all done!


;These are the strings used in the program:

Title_1: .db "Columns  v3.0", 0
Title_2: .db "by Mel Tsai (c)1996", 0
Title_3: .db "tsaimelv@pilot.msu.edu", 0
Title_4: .db "Select Difficulty (L/R):", 0
Title_5: .db "Easy                     ", 0
Title_6: .db "Medium          ", 0
Title_7: .db "Hard                 ", 0
Title_8: .db "Very Hard       ", 0
Title_9: .db "Impossible      ", 0
Title_10: .db "Press 2nd to begin...", 0

Screen_1: .db "Blocks:",0
Screen_2: .db "Level:",0

GameOver_1:  .db "Game Over!!!", 0
GameOver_2:  .db "Final  Score:", 0
GameOver_3:  .db "New High Score!", 0
GameOver_4:  .db "Please Enter Initials:", 0
GameOver_5:  .db "High Scores:", 0

;edit this to change speed in which the blocks fall...

DelayString: .dw 0,2300,2000,1700,1500,1300,1200,1100,1000,900

EasyScore:   .db "000",0,0,4
MedScore:    .db "000",0,0,5
HardScore:   .db "000",0,0,6
VHardScore:  .db "000",0,0,7
ImpScore:    .db "000",0,0,8

TeacherStr:
.db "Instructions:  Turn the " 
.db "calculator",0
.db "sideways (so the blocks "
.db "fall down)",0
.db "and get 3 blocks in a row!",0
.db "2ND- Rotates the block",0
.db "EXIT- Quit Game",0
.db "MORE- Pause/Unpause",0
.db "ENTER- Saves game and exits,",0
.db "press MORE upon returning.",0


ASCII_Table:                   ;Thanks to Magnus H. for this Table!!!
   .db 0,0,0,0,0,0,0,0,0       ;00-09 - not valid 
   .db 'X,'T','O','J','E'      ;0A-0E - valid
   .db 0,0                     ;0F-10 - not valid
   .db ' ','W','S','N','I'     ;11-15 - valid
   .db 'D'                     ;16    - valid
   .db 0,0                     ;17-18 - not valid
   .db 'Z','V','R','M','H','C' ;19-1E- valid
   .db 0,0                     ;1F-20 - not valid
   .db 'Y','U','Q','L','G','B' ;21-26 - valid
   .db 0,0,0,0                 ;27-2A - not valid
   .db 'P','K','F','A'         ;2B-2E - valid
   .db 0,0,0,0,0,0,0,0,0,0     ;Rest  - not valid


; These bytes are where a game is saved into memory when "enter" is pressed.

GameSaved: .db 0

SaveMemory: 
.dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.dw 0,0,0,0,0,0,0,0,0,0

; 140 memory bytes


.end
