; *************************************************** ; * ; * T E T R I S 9 7 ; * ; * ; * Programmed by Patrick Davidson ; * ; * last updated : 26-Jul-97 ; * ; *************************************************** ; -------------- PROGRAM HEADER -------------------- .org 0 .include "usgard.h" .include "lib/usgdlib.h" .db "Tetris 97u.06 by Patrick D" .db 0 .db USGDLIB,0 ; -------------- VARIABLE ADDRESSES ---------------- scrlstart =$8010 scrlpos =$8012 temp =$8014 score =$8016 lines =$8018 delay =$801a px =$801c py =$801d level =$801e piece =$8020 tpiece =$8030 exitstack =$8040 tpx =$8042 tpy =$8043 fit =$8046 speed_up =$8047 already_rot =$8048 rptr =$8049 linesnow =$804b leftc =$804d rightc =$804e skd =$8055 world =$80df off_px =px-$8010 off_py =py-$8010 off_tpx =tpx-$8010 off_tpy =tpy-$8010 off_fit =fit-$8010 off_ar =already_rot-$8010 off_ln =linesnow-$8010 off_level =level-$8010 off_lc =leftc-$8010 off_rc =rightc-$8010 off_delay =delay-$8010 off_su =speed_up-$8010 ; -------------- INITIALIZATION CODE --------------- ld (iy+13),0 ld (iy+5),2 ROM_CALL(CLEARLCD) ld b,96 ld a,32 ld ix,$8641 pcl: ld hl,0 ld ($800c),hl push af push bc ROM_CALL(TX_CHARPUT) ld hl,$fc00 ld b,8 ld de,16 il2: ld a,(hl) ld (ix),a sla a or (ix) ld (ix),a add hl,de inc ix djnz il2 pop bc pop af inc a djnz pcl ld a,1 ld (USG_BITS),a ld ix,$800f ld b,101 clr_delc:ld (ix),0 inc ix djnz clr_delc ld hl,(&random) ld (rptr),hl call &display_ttl_scr call &play_game ld a,%00111111 out (1),a in a,(1) bit 7,a jr z,exit_now not_2nd: call &your_score ROM_CALL(CLEARLCD) ld hl,0 ld ($800c),hl ld hl,&hstitle ROM_CALL(D_ZT_STR) ld hl,$1001 ld ($800c),hl ld ix,&hsdata ld b,7 ld de,17 high_display_loop: ld l,(ix+0) ld h,(ix+1) push bc push de push hl ROM_CALL(D_HL_DECI) pop hl pop de pop bc ld hl,$800c dec (hl) inc ix inc ix push ix pop hl ROM_CALL(D_ZT_STR) add ix,de ld hl,$800c inc (hl) inc hl ld (hl),16 djnz high_display_loop loop_wk: call GET_KEY or a jr z,loop_wk exit_now: ld hl,(rptr) ld (&random),hl ret ; -------------- SCORING --------------------------- gameover:.db "GAME OVER!",0 your_score: ld hl,$3832 ld ($8333),hl ld hl,&gameover ROM_CALL(D_ZM_STR) call GET_KEY wkls: call GET_KEY or a jr z,wkls ld hl,&lowest ;See if ya got a hi-score call LD_HL_MHL ld de,(score) call CP_HL_DE ret nc ROM_CALL(CLEARLCD) ld hl,0 ld ($800c),hl ld hl,&hi_score_str ROM_CALL(D_ZT_STR) ld ix,&lowest+2 ld c,16 ld A,%00010000 LIB_CALL_(USGDLIB,INPST) nomore: ld hl,(score) ld (&lowest),hl ld ix,&lowest ld b,6 sort_scores: ld e,(ix) ld d,(ix+1) ld l,(ix-19) ld h,(ix-18) call CP_HL_DE ret nc push bc ld b,19 ld d,0 exg_loop:ld e,(ix) ld c,(ix-19) ld (ix),c ld (ix-19),e inc ix djnz exg_loop ld de,-38 add ix,de pop bc djnz sort_scores ret ; -------------- TITLE SCREEN ---------------------- display_ttl_scr: ROM_CALL(CLEARLCD) ld hl,0 ld ($800c),hl ld (score),hl ld hl,&title ROM_CALL(D_ZT_STR) ld ix,$800c inc (ix) ROM_CALL(D_ZT_STR) inc (ix) ROM_CALL(D_ZT_STR) ld hl,&scrltext ld (scrlstart),hl ld hl,$0806 ld ($8941),hl intro_loop: ld hl,$89c1 ld b,128 clrg: ld (hl),0 inc hl djnz clrg ld hl,(scrlpos) inc hl ld (scrlpos),hl ld de,(scrl_end-scrltext)*8 call CP_HL_DE jr nz,not_end_of_text ld hl,0 ld (scrlpos),hl not_end_of_text: ld de,(scrlpos) ld hl,(scrlstart) ld b,3 fspl: res 0,e srl d jr nc,no_ovfs set 0,e no_ovfs: rrc e djnz fspl add hl,de ld b,15 ld a,(scrlpos) cpl and 7 ld e,a scroll: ld a,(hl) inc hl push hl push bc ld hl,$8541 push de ld de,8 ld b,a scroll_draw: add hl,de djnz scroll_draw ld b,8 ld ix,$8943 copy_char: ld a,(hl) ld (ix),a inc ix inc hl djnz copy_char pop de ld b,e ld c,56 ld ix,$8941 push de call &drw_spr pop de ld a,e add a,8 ld e,a pop bc pop hl djnz scroll ld ix,$89c1 ld b,8 blocks__:ld (ix),255 ld (ix+15),255 push bc ld bc,16 add ix,bc pop bc djnz blocks__ ld hl,$89c1 ld de,$ff80 ld bc,128 ldir call GET_KEY ld (skd),a or a jp z,&intro_loop ret title: .db "T E T R I S 9 7 U",0 .db "by Patrick A Davidson" .db " (ariwsi@juno.com) ",0 .db " Copyright 1997",0 .db 0 scrltext:.db " " .db "WELCOME TO TETRIS 97! " .db "PRESS ANY KEY TO START " .db "PLAYING. USE THE FUNCITON " .db "KEYS TO START A FASTER " .db "LEVEL. PRESS MORE TO " .db "SAVE THE GAME AND EXIT. " .db "THE SOURCE CODE TO THIS " .db "GAME IS 1,133 LINES LONG! " .db " TEXT RESTARTS ... " scrl_end:.db " " ; ---------------------- HIGH SCORES ------------------------- hi_score_str: .db "----> TETRIS 97 <----" .db " You have a hiscore!" .db "Enter your name here:",0 hstitle: .db "= TETRIS HIGHSCORES =",0 hsdata: .dw 666 .db "Bill Gates ",0 .dw 666 .db "Bill Gates ",0 .dw 666 .db "Bill Gates ",0 .dw 666 .db "Bill Gates ",0 .dw 666 .db "Bill Gates ",0 .dw 666 .db "Bill Gates ",0 lowest .dw 666 .db "Bill Gates ",0 ; -------------- THE ACTUAL GAME ------------------- play_game: ld (exitstack),sp ROM_CALL(CLEARLCD) ld hl,0 ld ($800c),hl ld hl,&initialtemplate ROM_CALL(D_ZT_STR) ld de,$1000 ld ($800c),de ROM_CALL(D_ZT_STR) ld de,$0201 ld ($800c),de ROM_CALL(D_ZT_STR) ld de,$0003 ld ($800c),de ROM_CALL(D_ZT_STR) ld a,$10 ld ($800d),a ROM_CALL(D_ZT_STR) ld de,$0105 ld ($800c),de ROM_CALL(D_ZT_STR) ld de,$1006 ld ($800c),de ROM_CALL(D_ZT_STR) ld a,100 ld (delay),a ld ix,$fc00 ld b,64 ld de,16 sidelines: ld (ix+5),1 ld (ix+11),128 add ix,de djnz sidelines ld hl,&saved_flag ld a,(hl) or a jp nz,&restore_da_game ld ix,$8010 LD (ix+off_su),-12 ld a,(skd) sub $31 bit 7,a jr nz,main_loop neg add a,5 bit 7,a jr nz,main_loop ld b,a skip: push bc ld b,10 skipe: dec (ix+off_delay) inc (ix+off_level) djnz skipe pop bc djnz skip main_loop: call &makep call &testfit ld a,(ix+off_fit) or a ret z restore_label: ld hl,(rptr) inc hl res 7,h ld a,(hl) call &extract_piece ld ix,$ff00 call &do_next ld hl,(rptr) inc hl inc hl res 7,h ld a,(hl) call &extract_piece ld ix,$ff03 call &do_next ld ix,$8010 call &redrawboard call &plop call &putp call &lines_ inc (ix+off_su) ld a,4 cp (ix+off_su) jr nz,main_loop ld (ix+off_su),0 ld a,1 cp (ix+off_delay) jr z,main_loop dec (ix+off_delay) inc (ix+off_level) jr main_loop ret exit_game: ld sp,(exitstack) ret initialtemplate: .db "TETRIS",0 .db "SCORE",0 .db "97",0 .db "BY PAD",0 .db "LINES",0 .db "NEXT",0 .db "LEVEL",0 ; -------------- MAIN LOOP ------------------------- plop: call &luser call &luser call &luser call &luser call &luser call &undraw inc (ix+off_tpy) call &testfit call &drawp ld a,(ix+off_fit) or a ret z jr plop ; -------------- SAVE AND EXIT --------------------- save_exit: ld &hl,saved_flag ld (hl),1 inc hl push hl pop de ld hl,$8016 ld bc,25 ldir ld hl,$80df ld b,20 loop_crunch_outer: push bc ld a,(hl) inc hl ld b,7 loop_crunch_inner: sla a or (hl) inc hl djnz loop_crunch_inner ld (de),a inc de pop bc djnz loop_crunch_outer ld a,3 ld (USG_BITS),a jp &exit_game ; -------------- RESTORE A SAVED GAME -------------- restore_da_game: ld (hl),0 inc hl ld de,$8016 ld bc,25 ldir push hl pop de ld hl,$80df ld b,20 loop_decrunch_outer: push bc ld a,(de) inc de ld b,8 loop_decrunch_inner: ld (hl),0 bit 7,a jr z,no___block ld (hl),1 no___block: inc hl sla a djnz loop_decrunch_inner pop bc djnz loop_decrunch_outer jp &restore_label ; -------------- READ INPUT ------------------------ luser: ld a,%00111111 out (1),a in a,(1) bit 6,a jp z,&exit_game bit 7,a jr z,save_exit call &delay_ call &undraw ld de,tpiece ld hl,piece ld bc,16 ldir ld a,%01111110 out (1),a in a,(1) bit 0,a jr nz,not_down inc (ix+off_tpy) not_down:bit 1,a jr z,go_left ld (ix+off_lc),0 left_r: inc (ix+off_lc) bit 2,a jr z,go_right ld (ix+off_rc),0 right_r: inc (ix+off_rc) bit 3,a jr z,rotate ld (ix+off_ar),0 rfr: call &testfit jp &drawp go_right:push af ld a,(ix+off_rc) cp 1 jr z,dg_right cp 3 jr nc,dg_right pop af jr right_r dg_right:inc (ix+off_tpx) pop af jr right_r go_left: push af ld a,(ix+off_lc) cp 1 jr z,dg_left cp 3 jr nc,dg_left pop af jr left_r dg_left: dec (ix+off_tpx) pop af jr left_r ; -------------- ROTATE THE PIECE ------------------ rotate: ld a,(ix+off_ar) or a jr nz,rfr ld (ix+off_ar),1 ld b,3 ;(b,c)=(x,y) ld d,0 rol: ld c,3 ril: ld hl,piece ld a,c sla a sla a add a,b ld e,a add hl,de ld a,(hl) push af ld hl,tpiece ld a,c cpl and 3 add a,b add a,b add a,b add a,b ld e,a add hl,de pop af ld (hl),a dec c bit 7,c jr z,ril dec b bit 7,b jr z,rol jr rfr ; -------------- MAKE A PIECE ---------------------- makep: ld a,-1 ld (tpy),a ld a,4 ld (tpx),a ld hl,(rptr) inc hl res 7,h ld (rptr),hl ld a,(hl) extract_piece: ld hl,&pieces and 7 ld c,a ld b,0 add hl,bc ld b,4 ld ix,tpiece upperl: ld (ix),0 ld (ix+12),0 inc ix djnz upperl ld a,(hl) ld b,8 piecunpk:ld (ix),0 bit 7,a jr z,nothere ld (ix),1 nothere: rlc a inc ix djnz piecunpk ld ix,$8010 ret pieces: .db %11110000 .db %11110000 .db %01100110 .db %00100111 .db %01100011 .db %00110110 .db %00101110 .db %01000111 ; -------------- TEST IF A PIECE FITS -------------- testfit: ld (ix+off_fit),0 ld b,3 ;(b,c)=(x,y) tfol: ld c,3 tfil: ld hl,tpiece ld d,0 ld a,c sla a sla a add a,b ld e,a ;E = offset into piece for (b,c) add hl,de ;HL = address in piece for (b,c) ld a,(hl) ;Test if this segemnt is a block or a jr z,blank3 ld a,b add a,(ix+off_tpx) ;A = world X coordinate ret m ;Match failed if negative ld e,a ;Match failed if >=10 sub 10 ret nC sla e sla e sla e sla e ;E = X coord * 16 ld a,c add a,(ix+off_tpy) ;A = world Y coordinate bit 7,a jr nz,blank3 bit 4,a ret nz add a,e ld e,a ;E = map offset ld hl,world add hl,de ld a,(hl) or a ret nz blank3: dec c bit 7,c jr z,tfil dec b bit 7,b jr z,tfol ld de,piece ld hl,tpiece ld bc,16 ldir ld hl,(tpx) ld (px),hl ld (ix+off_fit),-1 ret ; -------------- REDRAW THE BOARD ------------------ redrawboard: ld ix,world ld hl,$fc06 ld b,5 rdol: push bc ld b,16 rdil: ld a,0 bit 0,(ix) jr z,no1 ld a,240 no1: bit 0,(ix+16) inc ix jr z,no2 or 15 no2: push bc ld b,4 ld de,16 bla_whatever: ld (hl),a ADD hl,de djnz bla_whatever pop bc djnz rdil pop bc ld de,-1023 add hl,de ld de,16 add ix,de djnz rdol ld hl,$1001 ld ($800c),hl ld hl,(score) ROM_CALL(D_HL_DECI) ld hl,$1004 ld ($800c),hl ld hl,(lines) ROM_CALL(D_HL_DECI) ld hl,$1007 ld ($800c),hl ld hl,(level) ROM_CALL(D_HL_DECI) ret ; -------------- PUT A PIECE INTO THE WORLD MAP ---- putp: ld b,3 ppol: ld c,3 ppil: ld hl,piece ld d,0 ld a,c sla a sla a add a,b ld e,a ;E = offset into piece for (b,c) add hl,de ;HL = address in piece for (b,c) ld a,(hl) ;Test if this segemnt is a block or a jr z,blank8 ld a,b add a,(ix+off_px) ;A = world X coordinate ld e,a sla e sla e sla e sla e ;E = X coord * 16 ld a,c add a,(ix+off_py) ;A = world Y coordinate bit 7,a jr nz,blank8 add a,e ld e,a ;E = map offset ld hl,world add hl,de ld (hl),1 blank8: dec c bit 7,c jr z,ppil dec b bit 7,b jr z,ppol ret ; -------------- ERASE LINES ----------------------- lines_: ld (ix+off_ln),0 ld hl,$80ee ld b,15 linesi: push hl ld a,255 ld de,16 ld c,b ld b,10 loopil: and (hl) add hl,de djnz loopil ld b,c pop hl or a jr z,no_line push bc push hl ld b,0 ld ($8641),bc ld b,10 lul: push hl push hl pop de dec hl push bc ld bc,($8641) lddr pop bc ld a,0 ld (de),a pop hl ld de,16 add hl,de djnz lul pop hl pop bc inc (ix+off_ln) inc hl inc b no_line: dec hl djnz linesi ld b,(ix+off_ln) ld a,0 cp b ret z ld a,128 loopsco: rlc a rlc a djnz loopsco ld c,a ld b,0 ld hl,(level) add hl,bc ld de,(score) add hl,de ld (score),hl ld hl,(lines) ld c,(ix+off_ln) ld b,0 add hl,bc ld (lines),hl ret ; -------------- DRAW A PIECE ---------------------- drawp: ld b,3 ;(b,c)=(x,y) dpol: ld c,3 dpil: ld hl,piece ld d,0 ld a,c sla a sla a add a,b ld e,a add hl,de ld a,(hl) or a jr z,blank2 ld a,b add a,(ix+off_px) ld d,a ld a,c add a,(ix+off_py) ld e,a call &draw_block blank2: dec c bit 7,c jr z,dpil dec b bit 7,b jr z,dpol ret ; -------------- ERASE A PIECE --------------------- undraw: ld b,3 ;(b,c)=(x,y) udol: ld c,3 udil: ld hl,piece ld d,0 ld a,c sla a sla a add a,b ld e,a add hl,de ld a,(hl) or a jr z,blank ld a,b add a,(ix+off_px) ld d,a ld a,c add a,(ix+off_py) ld e,a call &eraseblock blank: dec c bit 7,c jr z,udil dec b bit 7,b jr z,udol ld de,tpiece ld hl,piece ld bc,16 ldir ld hl,(px) ld (tpx),hl ret ; -------------- DRAW A SQUARE AT (d,e) ------------- draw_block: bit 7,c ret nz push bc ld ix,$fbc6 ld b,e inc b push de ld de,64 lbl1: add ix,de djnz lbl1 pop de bit 0,d ld a,15 jr nz,lbl2 ld a,240 lbl2: ld e,d srl e ld d,0 add ix,de or (ix) ld (ix),a ld (ix+16),a ld (ix+32),a ld (ix+48),a pop bc ld IX,$8010 ret ; -------------- ERASE A SQUARE AT (d,e) ------------ eraseblock: bit 7,c ret nz push bc ld ix,$fbc6 ld b,e inc b push de ld de,64 lbl3: add ix,de djnz lbl3 pop de bit 0,d ld a,15 jr z,lbl4 ld a,240 lbl4: ld e,d srl e ld d,0 add ix,de and (ix) ld (ix),a ld (ix+16),a ld (ix+32),a ld (ix+48),a pop bc ld ix,$8010 ret ; -------------- SLOW DOWN THE GAME ----------------- delay_: push bc ld hl,(delay) delayi: ld b,0 slow___: djnz slow___ push hl ld de,0 call CP_HL_DE pop hl dec hl jr nz,delayi pop bc ret ; -------------- SPRITE RENDERING ROUTINE ---------- drw_spr: ld e,128 ;FindPixel NO MORE !!!!!!!!!!!!!!! push bc ld a,b and 7 ;Calculate bit number jr z,done ld b,a bit_loop:srl e djnz bit_loop done: pop bc clbl1: ld hl,$8641 ;Calculate byte number srl b srl b srl b ld a,b ;A = x shift right (bytes) sla c sla c ld b,c sla c sla c ;C = 8 LSBs of Y offset or c ;A = 8 LSBs of offset ld c,a ;C = 8 LSBs of offset rlc b rlc b ld a,b and 3 ld b,a ;B = 2 MSBs of offset add hl,bc ;HL = address ld d,(ix) ;C is width inc ix ld b,(ix) ;C is height inc ix oloop: push bc ;Save # of rows push hl ;Save screen address ld b,d ;Load width ld c,(ix) ;Load one line of image inc ix ld a,e ;Load pixel mask iloop: bit 7,c ;Test leftmost pixel jr z,noplot ;See if a plot is needed push af ;OR pixel with screen or (hl) ld (hl),a pop af noplot: rrc a ;Move bit mask to next pixel sla c ;Slide image one pixel bit 7,a ;Check if time for next byte jr z,notedge ;Test if edge of byte reached inc hl ;Go to next byte notedge: djnz iloop pop hl ;Restore address ld bc,16 ;Go to next line add hl,bc pop bc ;Restore data djnz oloop ret ; -------------- DO A SECTION OF THE NEXT PIECE --------- ns: ld a,0 bit 0,(hl) jr z,no777 ld a,240 no777: inc hl bit 0,(hl) inc hl jr z,no1911 or 15 no1911: ld (ix),a ld (ix+16),a ld (ix+32),a ld (ix+48),a inc ix ret do_next: ld hl,tpiece ld b,4 next_loop: call &ns call &ns ld de,62 add ix,de djnz next_loop ret random: .dw $1234 saved_flag: .db 0 savedata:.dw 0,0,0,0,0,0,0,0,0,0,0,0 .db 0 save_map:.dw 0,0,0,0,0,0,0,0,0,0 .end