;This is the code for Ricochet v1.0, the first
;game I wrote for ASM, and the first game I ever
;designed myself. I don't think it's very good,
;but if you can, have fun!
;
;Notice: This code is MINE (Well, most of it)!
;Don't steal or modify it without my permission.
;It can be freely destributed for the purposes of
;seeing how it works (and stinks) and for learning
;ASM. Note that this is the first program in ASM
;that I started, and that it may have many bad
;habits and wierdnesses.
;
;Routines used in this program are by Dan Eble,
;Magnus Hagander, Chris Busch (for part of the
;random number generator), and of course, ME!
;
;Report bugs, comments, and suggestions (no flames
;please!) to micahbro@msn.com. (I'm calling the
;wierdness where the ball can pass through the
;paddle when you RUN into it a "feature," not a
;bug.)
;
;This version does NOT support multiple keys at
;once. It is faster than the version that does and
;it is not flakey. The other version should also
;be available. If you can fix it, do so, and email
;the patched code to me. I will release it, when I
;get a chance (I'm leaving for 3 wks on 7/14/96,
;returning for a weekend, and leaving for 3 wks
;again).
;
;--MZB (Micah Z. Brodsky, micahbro@msn.com,
;micah_brodsky@lakeside.sea.wa.us during school)
;
;(C)-1996, this text - 7/8/96

#INCLUDE "TI-85.H"

;Text mem variable defs
BALLY	=$80DF
BALLX	=$80E0
BALLAY	=$80E1	;up
BALLAX	=$80E2	;right
BLOCKY	=$80E3
BLOCKX	=$80E4
MOVLAST	=$80E5	;moved block on last loop
LINEY	=$80E6
LINEON	=$80E7
LONLAST =$80E8	;line on last loop
SCORE	=$80E9
LIVES	=$80EA
LCOUNT	=$80EB	;line on or off keeper tracker
MNUM	=$80EC
MNUM2	=$80ED	;not used as MNUMx
MNUM3	=$80EE	;not used as MNUMx
MNUM4	=$80EF	;not used as MNUMx
MNUM5	=$80F0	;not used as MNUMx

.org 0
.db "Ricochet! v1.0", 0
	ld a, 4			;} set mem page
	out (5), a		;}

Initrand:		;Random generator (0-3),
        ld a, r		;built from Chris Busch and someone else's generators,
        cp $FF		;modified a bit by me (Micah Brodsky)
        jr nc, Initrand	;(I wanted one that didn't give 2 80% of the time;)
        cp 0
        jr c, Initrand
	ld b, a
	sla b
	sla b
	add a, b
	sla b
	sla b
	add a, b
	inc a
	srl a
	srl a
	srl a
	and $03

	cp 0
	jr nz, Skip0
	ld a, 67		;} init vars
	ld (BALLX), a		;}
	ld a, 35		;}
	ld (BALLY), a		;}
	ld a, 1			;}
	ld (BALLAX), a		;}
	ld (BALLAY), a		;}
	jr Skipall
Skip0:
	cp 1
	jr nz, Skip1
	ld a, 67		;} init vars
	ld (BALLX), a		;}
	ld a, 24		;}
	ld (BALLY), a		;}
	ld a, 1			;}
	ld (BALLAX), a		;}
	ld a, -1		;}
	ld (BALLAY), a		;}
	jr Skipall
Skip1:
	cp 2
	jr nz, Skip2
	ld a, 58		;} init vars
	ld (BALLX), a		;}
	ld a, 24		;}
	ld (BALLY), a		;}
	ld a, -1		;}
	ld (BALLAX), a		;}
	ld (BALLAY), a		;}
	jr Skipall
Skip2:
	ld a, 58		;} init vars
	ld (BALLX), a		;}
	ld a, 35		;}
	ld (BALLY), a		;}
	ld a, -1		;}
	ld (BALLAX), a		;}
	ld a, 1			;}
	ld (BALLAY), a		;}
Skipall:

	ld a, 63		;}
	ld (BLOCKX), a		;}
	sub 6			;}
	sla a			;}that's so the line moves 1/2 as fast as you
	ld (LINEY), a		;}
	ld a, 31		;}
	ld (BLOCKY), a		;}
	ld a, 1			;}
	ld (LINEON), a		;}
	ld (LONLAST), a		;}
	dec a			;}
	ld (SCORE), a		;}
	ld (LCOUNT), a		;}
	ld (LIVES), a		;}

	ROM_CALL(CLEARLCD)	;} Opening screen...
	set 3, (iy+5)		;}
	ld hl, 2		;}
	ld (CURSOR_ROW), hl	;}
	ld hl, (PROGRAM_ADDR)	;}
	ld de, Opening		;}
	add hl, de		;}
	ROM_CALL(D_ZT_STR)	;}
	res 3, (iy+5)		;}
Openingloop:			;}
	call GET_KEY		;}
	cp 0			;}
	jr z, Openingloop	;}
	ROM_CALL(CLEARLCD)	;}
	ld a, 1			;}
	CALL_(Drawblock)	;}
	ld de, $000A		;}
	CALL_(Updscore)		;}

Rebounce:			;Beginning of main loop (starts bouncing)
	ld a, (LIVES)
	sub 1
	bit 7, a		;cp 0 for non negative
	JUMP_NZ(Gameover)	;z for " "
	ld bc, (BALLY)		;uses bc as a quick access to ball coords
	ld a, (LONLAST)		;}if the line wasn't on, it can't hurt you
	cp 0			;}
	jr z, Contkline		;}
	ld a, (LINEY)		;Check for an impact...
	sra a
	ld l, a
	ld a, (BLOCKY)
	ld e, a
	add a, 3
	sub l
	bit 7, a
	jr nz, Contkline
	ld a, e
	sub 6
	sub l
	bit 7, a
	jr z, Contkline
	ld a, (LIVES)		;}a little formula for the # o' lives lost
	sra a			;}
	sra a 			;}
	add a, 2		;}
	neg			;}
	ld d, 0
	ld e, a
	CALL_(Updscore)		;update the score & lives
	ld a, -1
	ld (LCOUNT), a
	CALL_(Drawlineoff)	
	ld a, 1
	ld (LONLAST), a
	ld (MOVLAST), a
	CALL_(Drawblock)
Contkline:
	push bc			;}Draw the ball...
	CALL_(Pton)		;}bc,left,up,right: 0,63
	dec b			;}
	CALL_(Pton)		;}
	inc c			;}
	CALL_(Pton)		;}
	inc b			;}
	CALL_(Pton)		;}
	CALL_(Delay)
	ld a, (LONLAST)		;When the line or paddle was redrawn,
	cp 1				;don't delay...
	jr z, Skiplinedelay
	CALL_(Delay)
	ld a, (MOVLAST)
	cp 1
	jr z, Skipdelay
	CALL_(Shortdelay)
	CALL_(Delay)
Skiplinedelay:			;a little weirdness ;)
Skipdelay:
	ld a, 0
	ld (MOVLAST), a
	pop bc
	push bc
	ld a, (LCOUNT)		;update the line's position and status...
	inc a
	ld (LCOUNT), a
	sub 27			;27 (or 26) line off loops (maybe)
	bit 7, a
	jr z, Lineon
	ld a, 0
	ld (LINEON), a
	jr Startline
Lineon:
	cp 40			;40-27 (or +1) line on loops (maybe)
	jr nz, Contlineon
	ld a, 0
	ld (LCOUNT), a
Contlineon:
	ld a, 1
	ld (LINEON), a
Startline:
	ld a, 0			;line **(here can be optimized)** (redundancies in LINEON, LONLAST, Skipline)
	ld (LONLAST), a		;(but I never feel like it)
	ld a, (LINEON)		
	cp 0			;don't draw & LONLAST this time?
	jr z, Skipline
	CALL_(Drawlineoff)
	ld a, (LINEY)
	sra a
	ld hl, (BLOCKY)
	sub l
	bit 7, a
	jr z, Upline
	ld a, (LINEY)
	inc a
	ld (LINEY), a
	jr Uplinebypass
Upline:				
	ld a, (LINEY)		;update *2ed position
	dec a
	ld (LINEY), a
Uplinebypass:
	ld a, (LCOUNT)
	cp 0
	jr z, Skipline		;really, skip-redraw-line
	CALL_(Drawlineon)
	ld (LONLAST), a
Skipline:			;Check for bounces and update score...
	ld d, 1
	ld e, -1
	ld a, c			;bounce top?
	cp 56
	jr z, Ballju
	ld hl, (BLOCKY)		;for here and future use
	add a, 7
	cp l
	jr nz, Contju
	ld a, b
	add a, 4
	sub h
	bit 7, a
	jr nz, Contju
	ld a, b
	sub 6
	sub h
	bit 7, a
	jr z, Contju
	ld e, 2
Ballju:
	ld a, (BALLAY)
	bit 7, a
	jr nz, Contju
	CALL_(Updscore)
	ld a, -1
	ld (BALLAY), a
Contju:	
	ld a, b			;bounce lft?
	cp 1
	jr z, Balljl
	sub 6
	cp h
	jr nz, Contjl
	ld a, c
	add a, 6
	sub l
	bit 7, a
	jr nz, Contjl
	ld a, c
	sub 6
	sub l
	bit 7, a
	jr z, Contjl
	ld e, 2
Balljl:
	ld a, (BALLAX)
	bit 7, a
	jr z, Contjl
	CALL_(Updscore)
	ld a, 1
	ld (BALLAX), a
Contjl:	
	ld a, b			;bounce rt?
	cp 127
	jr z, Balljr
	add a, 5
	cp h
	jr nz, Contjr
	ld a, c
	add a, 6
	sub l
	bit 7, a
	jr nz, Contjr
	ld a, c
	sub 5
	sub l
	bit 7, a
	jr z, Contjr
	ld e, 2
Balljr:
	ld a, (BALLAX)
	bit 7, a
	jr nz, Contjr
	CALL_(Updscore)
	ld a, -1
	ld (BALLAX), a
Contjr:	
	ld a, c			;bounce dn?
	cp 0
	jr z, Balljd
	sub 4
	cp l
	jr nz, Contjd
	ld a, b
	add a, 4
	sub h
	bit 7, a
	jr nz, Contjd
	ld a, b
	sub 5
	sub h
	bit 7, a
	jr z, Contjd
	ld e, 2
Balljd:
	ld a, (BALLAY)
	bit 7, a
	jr z, Contjd
	CALL_(Updscore)
	ld a, 1
	ld (BALLAY), a
Contjd:	
	CALL_(Ptoff)		;}erase ball
	dec b			;}
	CALL_(Ptoff)		;}
	inc c			;}
	CALL_(Ptoff)		;}
	inc b			;}
	CALL_(Ptoff)		;}
	pop bc 
	ld de, (BALLAY)
	ld a, b
	add a, d
	ld b, a
	ld a, c
	add a, e
	ld c, a
	ld (BALLY), bc	
Chkkey:
	call GET_KEY
	cp $37
	JUMP_Z(Quit)
	cp $04			;Block movement checks
	jr nz, Contk04		;up
	ld a, (BLOCKY)
	cp 50
	jr z, Dorebounce
	ld a, 0
	CALL_(Drawblock)
	ld HL, BLOCKY
	inc (HL)
	inc a
	CALL_(Drawblock)
	jr Kdorebounce
Contk04:
	cp $01
	jr nz, Contk01
	ld a, (BLOCKY)
	cp 9
	jr z, Dorebounce
	ld a, 0
	CALL_(Drawblock)
	ld HL, BLOCKY
	dec (HL)
	inc a
	CALL_(Drawblock)
	jr Kdorebounce
Contk01:
	cp $02
	jr nz, Contk02
	ld a, (BLOCKX)
	cp 8
	jr z, Dorebounce
	ld a, 0
	CALL_(Drawblock)
	ld HL, BLOCKX
	dec (HL)
	inc a
	CALL_(Drawblock)
	jr Kdorebounce
Contk02:
	cp $03
	jr nz, Contk03
	ld a, (BLOCKX)
	cp 119
	jr z, Dorebounce
	ld a, 0
	CALL_(Drawblock)
	ld HL, BLOCKX
	inc (HL)
	inc a
	CALL_(Drawblock)
	jr Kdorebounce
Kdorebounce:
	ld a, 1			;Prepare to skip next delay
	ld (MOVLAST), a
Contk03:
Dorebounce:
	JUMP_(Rebounce)
Gameover:
	ld hl, $0603
	ld (CURSOR_ROW), hl
	ld hl, (PROGRAM_ADDR)
	ld de, Gameovertxt
	add hl, de
	ROM_CALL(D_ZT_STR)
Gameovrklp:
	call GET_KEY
	cp 9
	jr z, Quit
	cp $37
	jr nz, Gameovrklp
	
Quit:
	ret

;Self-use only subs
Updscore:			;d is score change, e is lp to change
	push hl
	ld a, 0
	ld (CURSOR_X), a
	ld (CURSOR_Y), a
	push de
	ld hl, (PROGRAM_ADDR)
	ld de, Score
	add hl, de
	ROM_CALL(D_ZM_STR)	;print "Score:
	pop de
	ld a, (SCORE)
	add a, d
	ld l, a
	ld h, 0
	ld (SCORE), a
	CALL_(Dhlmenutxt)	;print actual number
	push de
	ld hl, (PROGRAM_ADDR)
	ld de, Lives
	add hl, de
	ROM_CALL(D_ZM_STR)	;print "Lives:
	pop de
	ld a, (LIVES)		;print actual number
	add a, e
	ld l, a
	ld h, 0
	ld (LIVES), a
	CALL_(Dhlmenutxt)
	pop hl
	ret

Drawlineon:			;draw the line fast by writing directly
	push bc				;to VIDEO_MEM
	push hl
	ld bc, (LINEY)
	sra c
	ld b, 0
	ROM_CALL(FIND_PIXEL)
	ld b, 16
	ld de, VIDEO_MEM
	add hl, de
LineonLoop:
	ld (hl), $FF
	inc hl
	djnz LineonLoop
	pop hl
	pop bc
	ret

Drawlineoff:				;erase the line the same way
	push bc
	push hl
	ld bc, (LINEY)
	sra c
	ld b, 0
	ROM_CALL(FIND_PIXEL)
	ld b, 16
	ld de, VIDEO_MEM
	add hl, de
LineoffLoop:
	ld (hl), $00
	inc hl
	djnz LineoffLoop
	pop hl
	pop bc
	ret

Drawblock:			;requires a to be set to nonzero to draw, zero to erase
	push bc				;draws OR erases the paddle block
	push de
	push af
	push hl
	ld h, a
	ld bc, (BLOCKY)
	ld a, c
	sub 6
	ld c, a
	add a, 9
	ld e, a
	ld a, b
	sub 5
	ld b, a
	add a, 9
	ld d, a
	ld l, b
Blockoutloop:
	inc c
	push bc
Blockinloop:
	inc b
	push de
	ld a, h
	cp 0
	jr z, Blockonbypass
	CALL_(Pton)
	jr Blockoffbypass
Blockonbypass:			;Routine was cut&pasted to kill a few superfluous instructions
	push bc                  ;Save away, so it can be used again
	ROM_CALL(FIND_PIXEL)     ;Get the pixel offset
	ld   de,$FC00
	add  hl,de               ;Point into graphics memory   
	xor  255                 ;Invert the accumulator
	and  (hl)                ;A now contains the modified screen byte
	ld   (hl),a              ;Write back to screen to update
	pop bc                  ;Restore
	ld h, 0
Blockoffbypass:	
	pop de
	ld a, b
	cp d
	jr nz, Blockinloop
	pop bc			;Blockinloop has ended
	ld a, c
	cp e
	jr nz, Blockoutloop
	pop hl
	pop af
	pop de			;Blockoutloop had ended
	pop bc
	ret

;Sub for displaying hl in menu text
;There probably is an easier way, but I don't know it.
Dhlmenutxt:		;'kills DE
 	push de
	push bc
	push hl
	push af
	ld c, 0
	ld b, 5		;A word fits into 5 characters
ConvLoop:
 	call UNPACK_HL	;Unpack the next number
 	add a, '0'	;Now A is the CHARACTER for this value
	push hl
	ld hl, MNUM
	ld c, b
	ld b, 0
	add hl, bc
	ld b, c
	ld (hl), a
	pop hl
	djnz ConvLoop	;Convert all the 5 characters
	ld b, 0
Disploop:		;reorder the digits so that they go the right way
	inc b
	ld a, b
	cp 6
	jr z, Exitdisploop
	ld hl, MNUM
	ld c, b
	ld b, 0
	add hl, bc
	ld b, c
	ld a, (hl)
	ROM_CALL(M_CHARPUT)
	jr Disploop
Exitdisploop:
	pop af
	pop hl
	pop bc
	pop de
	ret	

;Universal subs:
;The following routines were created by the creators of ZShell
;(not including Shortdelay)
Pton:
	push bc                  ;Save away, so it can be used again
	ROM_CALL(FIND_PIXEL)     ;Get the pixel offset
	ld   de,$FC00
	add  hl,de               ;Point into the graphics memory
	or   (HL)                ;A now contains the modified screen byte
	ld   (HL),A              ;Write back to screen to update
	pop  bc                  ;Restore
	ret

Ptoff:
	push hl
	push bc                  ;Save away, so it can be used again
	ROM_CALL(FIND_PIXEL)     ;Get the pixel offset
	ld   de,$FC00
	add  hl,de               ;Point into graphics memory   
	xor  255                 ;Invert the accumulator
	and  (hl)                ;A now contains the modified screen byte
	ld   (hl),a              ;Write back to screen to update
	pop bc                  ;Restore
	pop hl
	ret



Delay:				;just keeps looping to make a ~precise delay
	push af
	push bc
	ld bc, $A00
DelayLoop:
	dec bc
	ld a, b
	or c
	jr nz, DelayLoop
	pop bc
	pop af
	ret

Shortdelay:
	push af
	push bc
	ld bc, $200
	jr DelayLoop

;Strings:
Gameovertxt:
.db "Game Over!",0
Score:
.db "Score: ", 0
Lives:
.db "       Lives: ", 0			;quick and easy indent
Opening:
.db "   Ricochet! v1.0    "		;fits the screen exactly, so it
.db "  By Micah Brodsky   "			;can be 1 string
.db "      (C)-1996       ", 0
.end
