;+------------------------------------------------------+ ;| JezzBall v1.1 | ;| by Joe Wingbermuehle | ;| 07-04-1998 | ;+------------------------------------------------------+ ; Home Page: http://www.usmo.com/~joewing ; Email: joewing@usmo.com ; This file is best viewed with Notepad (of course). .nolist #include "joeti83.inc" ; TI-83 ROM/RAM equates #include "sos.inc" ; SOS library equates ;-------+-= Variables =-+-----------------------------------------------+-------+ ; Name | Location | Description | Size | ;-------+---------------+-----------------------------------------------+-------+ nballs =sram ; number of balls | 1 | balls =sram+1 ; 3*8 matrix with ball data (x,y,direction) | 24 | xc =sram+25 ; x location for sprite | 1 | yc =sram+26 ; y location for sprite | 1 | loc =sram+27 ; location of sprite | 2 | playerx =sram+29 ; player x location | 1 | playery =sram+30 ; player y location | 1 | linel =sram+31 ; line length | 1 | ballc =sram+32 ; ball count - delay for moving ball/line | 1 | lined =sram+33 ; line direction | 1 | linet =sram+34 ; is the line still moving up? | 1 | lineb =sram+35 ; is the line still moving down? | 1 | wcount =sram+36 ; delay for swapping cursor | 1 | linex =sram+37 ; line x position | 1 | liney =sram+38 ; line y position | 1 | playerd =sram+39 ; player direction | 1 | lflag =sram+40 ; losser/winner flag | 1 | stop1 =sram+41 ; left/top stop point for line | 1 | stop2 =sram+42 ; right/bottom stop point for line | 1 | score =sram+43 ; the score | 2 | lives =sram+45 ; lives left | 1 | temp =sram+46 ; temporary variable - level/area count | 2 | speedt =sram+47 ; temporary variable - speed (2nd half of temp) | n/a | scount =sram+48 ; timer variable for score | 1 | fillx1 =sram+49 ; fill 1st x coordinate | 1 | filly1 =sram+50 ; fill 1st y coordinate | 1 | fillx2 =sram+51 ; fill 2nd x coordinate | 1 | filly2 =sram+52 ; fill 2nd y coordinate | 1 | ;-------+---------------+-----------------------------------------------+-------+ .org $9327 ; program offset for the TI-83 .list ;-----------= Header Data for SOS =----------- ccf ; 1-byte instruction for SOS compatability jr z,prog_start ; "invisible" until Install is run .dw libraries-$9327 ; pointer to libraries .dw name+1 ; pointer to description prog_start: ;---------= Beginning of JezzBall =--------- top: ld a,(slev) dec a ld (nballs),a ld b,8 ld hl,balls tplp: push bc ld b,65 call vector2 inc a inc a ld (hl),a ld b,55 call vector2 inc a inc a inc hl ld (hl),a inc hl ld b,4 call vector2 ld (hl),a inc hl pop bc djnz tplp ;---------- Menu ---------- menu: call menudraw ld hl,$170A ld (pencol),hl ld hl,info1 call vputs ld de,$1E0A ld (pencol),de call vputs ld de,$250A ld (pencol),de call vputs menulp: call getk cp 54 ; 2nd jp z,starta cp 48 ; alpha jp z,setlevel cp 56 ; del jr nz,menulp ret ;---------- Set Start Level ---------- setlevel: call menudraw ld a,(slev) dec a ld (temp),a ld a,(speed) ld (speedt),a ld hl,$250A ld (pencol),hl ld hl,info6 call vputs ld de,$2C0A ld (pencol),de call vputs sllp: ld hl,$170A ld (pencol),hl ld hl,info4 call vputs ld a,(temp) inc a call setxxop1 ld a,$01 call dispop1a ld hl,$1E0A ld (pencol),hl ld hl,info5 call vputs ld a,(speedt) call setxxop1 ld a,1 call dispop1a call wkey cp 48 ; alpha jr z,changeSpeed cp 54 ; 2nd jr z,ssl cp 4 ; up jr z,adslv dec a ; down jr z,sbslv cp 56-1 ; del jp z,menu jr sllp sbslv: ld a,(temp) dec a xslvx: and %00000111 ld (temp),a jr sllp adslv: ld a,(temp) inc a jr xslvx ssl: ld a,(temp) inc a ld (slev),a ld a,(speedt) ld (speed),a jp top changeSpeed: ld a,(speedt) inc a cp 4 jr nz,changeSpeedNR ld a,1 changeSpeedNR: ld (speedt),a jr sllp ;---------- Draw the basics of the menu screen ---------- menudraw: call clrscr ld hl,$0100 ld (currow),hl ld hl,name call putps ld bc,$0037 ld de,$5E37 call dark_line res 7,(iy+20) ld hl,$0901 ld (pencol),hl ld hl,about call vputs ld hl,$3801 ld (pencol),hl ld hl,hscr call vputs ld hl,(highscore) call setxxxxop2 call op2_to_op1 ld a,6 jp dispop1a ;---------- Start a level ---------- starta: ld hl,100 ld (score),hl ld a,30 ld (scount),a start: ld a,(nballs) inc a ld (nballs),a ld (lives),a cp $09 jp z,goverwon restart: call clrgbuf call ballx xor a sbc hl,hl ld (temp),hl ; reset area filled ld (ballc),a ld (playerd),a ld (lflag),a ld (linel),a ld (wcount),a ld a,$08 ld (ballc),a ld hl,30*256+40 ld (playerx),hl call player ;---------- Draw game screen ---------- ld bc,$0001 ld d,b ld e,$3F call dark_line ld b,$49 ld d,b call dark_line ld b,1 ld e,c call dark_line ld c,$3F ld e,c call dark_line set 7,(iy+$14) ld hl,(2*7+2)*256+75 ld (pencol),hl ld hl,hscr+2 call vputs ld hl,75 ld (pencol),hl ld hl,levtxt call vputs ld a,(nballs) call setxxop1 ld a,1 call dispop1a ld ix,lifepic ld l,9 ld a,78 ld b,5 call vector0 ld hl,8*256+78+8 ld (pencol),hl ld a,(lives) call setxxop1 ld a,1 call dispop1a set 4,(iy+20) ld bc,75*256+63-(7*2+1) ld de,94*256+63-(7*2+1) call dark_line ld c,63-(7*4+1) ld e,63-(7*4+1) call dark_line ld c,63-7 ld e,63-7 call dark_line ld a,76 ld l,31 ld bc,31*256+2 ld ix,jezzball call vector4 ;---------- Main game loop ---------- main: call vector1 ld a,(scount) dec a jr nz,contScore ld hl,(score) dec hl ld (score),hl ld a,h or l jp z,lostTime call setxxxxop2 ld hl,(7*3+1)*256+75 ld (pencol),hl call op2_to_op1 ld a,6 call dispop1a call vputblank call vputblank ld a,30 contScore: ld (scount),a ld a,(ballc) dec a jr nz,mains1 call contLine call mball ld a,1 mains1: ld (ballc),a ld bc,(speed-1) delay: ei ; just to make sure... halt djnz delay skipdelay: ld a,(lflag) dec a jp z,lost dec a jp z,start ld a,$FF out ($01),a ld a,$FE out ($01),a in a,($01) cp 253 jp z,mleft cp 251 jp z,mright cp 254 jp z,mdown cp 247 jp z,mup ld a,(wcount) or a jr z,noSkipMoves dec a ld (wcount),a jr skipMoves noSkipMoves: ld a,$DF out ($01),a in a,($01) cp 127 jp z,swapl skipMoves: ld a,$BF out ($01),a in a,($01) cp 223 jp z,startLine cp 191 jp z,pause cp 127 jp nz,main jr lost2 ;---------- We have a WINNER! ---------- goverwon: ld hl,winner jp exit lostTime: ld a,(lives) dec a ld (lives),a jp z,lost2 ld hl,100 ld (score),hl jp restart ;---------- We have a LOSSER! ---------- lost: ld a,(lives) dec a ld (lives),a jp nz,restart lost2: ld hl,losser exit: push hl call menudraw ld hl,4*256+3 ld (currow),hl pop hl call putps ld hl,1*256+5 ld (currow),hl ld de,(highscore) ld hl,(score) call vector5 ld (highscore),hl ld hl,nhs call z,puts exitLoop2: call getk or a jr nz,exitLoop2 ei halt call wkey jp top ;---------- Move right ---------- mright: call player ld a,$01 ld (playerd),a ld a,(playerx) inc a cp 69 jr z,movex ld (playerx),a movex: call player jp main ;---------- Move left ---------- mleft: call player ld a,$01 ld (playerd),a ld a,(playerx) dec a jr z,movex ld (playerx),a jr movex ;---------- Move up ---------- mup: call player xor a ld (playerd),a ld a,(playery) dec a jr z,movex ld (playery),a jr movex ;---------- Move down ---------- mdown: call player xor a ld (playerd),a ld a,(playery) inc a cp 58 jr z,movex ld (playery),a jr movex ;---------- Swap line direction ---------- swapl: call player ld a,20 ld (wcount),a ld a,(playerd) xor %00000001 ld (playerd),a call player jp main ;---------- Pause ---------- pause: ;call getkey ; for screen shot call wkey cp 56 jp z,lost2 pausex: jp main ;------------ Wait for a key press ------------ ; I use this method instead of GetKey to prevent ; apd which would mess up all the variables. wkey: call getk or a jr z,wkey ret ;---------- Turn player on/off ---------- player: ld hl,hsym ld a,(playerd) or a jr z,pls1 ld hl,vsym pls1: ld (loc),hl ld hl,(playerx) ld (xc),hl call sprite ret ;---------- Turn ball(s) on/off -------- ballx: ld hl,ball ld (loc),hl ld bc,(nballs-1) ld hl,balls ballxl: push bc ld a,(hl) ld (xc),a inc hl ld a,(hl) ld (yc),a inc hl inc hl push hl call sprite pop hl pop bc djnz ballxl ret ;---------- Move ball(s) ---------- mball: call player call ballx ld bc,(nballs-1) ld hl,balls ; hl points to balls mblp: push bc ld a,(hl) ; load ball data ld (xc),a inc hl ld a,(hl) ld (yc),a inc hl ld a,(hl) push hl ld d,a ; register d will hold direction mbd0: or a jp nz,mbd1 ld a,(xc) ; x+1,y+1 add a,5 ld (xc),a ld a,$01 call pixel call nz,mbChangeDir1 ld a,(xc) sub 4 ld (xc),a ld a,(yc) add a,5 ld (yc),a ld a,$01 call pixel jr z,mbd0s2 call mbChangeDir2 mbd0s2: ld a,(yc) sub 4 ld (yc),a jp mbx mbd1: dec a jp nz,mbd2 ld hl,xc ; x-1,y+1 dec (hl) dec (hl) ld a,$01 call pixel call nz,mbChangeDir1 ld hl,xc inc (hl) ld a,(yc) add a,5 ld (yc),a ld a,$01 call pixel call nz,mbChangeDir2 ld a,(yc) sub 4 ld (yc),a jp mbx mbd2: dec a jp nz,mbd3 ld hl,yc dec (hl) dec (hl) ld a,$01 call pixel call nz,mbChangeDir2 ld hl,yc inc (hl) ld a,(xc) ; x+1,y-1 add a,5 ld (xc),a ld a,$01 call pixel call nz,mbChangeDir1 ld a,(xc) sub 4 ld (xc),a jp mbx mbd3: ld hl,yc dec (hl) dec (hl) ld a,$01 call pixel call nz,mbChangeDir2 ld hl,yc inc (hl) ld hl,xc ; x-1,y-1 dec (hl) dec (hl) ld a,$01 call pixel call nz,mbChangeDir1 ld hl,xc inc (hl) mbx: pop hl ld a,d ld (hl),a dec hl ld a,(yc) ld (hl),a dec hl ld a,(xc) ld (hl),a inc hl ; point to yc inc hl ; point to direction inc hl ; point to next xc pop bc dec b jp nz,mblp call ballx jp player mbChangeDir1: ; add/sub 1 ld a,d xor %00000001 ld d,a ret mbChangeDir2: ; add/sub 2 ld a,d xor %00000010 ld d,a ret ;---------- Start a line ---------- startLine: ld a,(linel) or a jr nz,slx ld de,(playery) inc e inc e ld a,(playerx) inc a inc a call vector3 and (hl) jr z,slx ld a,1 ld (linel),a ld (linet),a ld (lineb),a ld hl,(playerx) ld (linex),hl ld a,(playerd) ld (lined),a slx: jp main ;---------- Continue a line ---------- contLine: ld a,(linel) or a ret z inc a ld (linel),a call player ld a,(lined) or a jr nz,cls1 ; Horizontal line call hLineTest ; check if a ball hit the line! ld a,(lineb) ; right side or a jr z,cls0a ; if not moving, then skip it! ld bc,(linel) ld a,(linex) ; line and add a,c ; set xc to it ld (xc),a ld (stop2),a ld a,(liney) ; the y position will not inc a ; change, however we need to inc a ; move to the middle of the ld (yc),a ; sprite (4/2=2 - add 2) ld a,$01 ; is this pixel call pixel ; aready on? jr z,cls0 ; if it is not, JUST turn it on xor a ; otherwise, set lineb to zero ld (lineb),a ; (skip this routine next call) cls0: xor a call pixel cls0a: ld a,(linet) ; left side or a jp z,clx ld bc,(linel) ld a,(linex) add a,3 sub c ld (xc),a ld (stop1),a ld a,(liney) inc a inc a ld (yc),a ld a,$01 call pixel jr z,cls0b xor a ld (linet),a cls0b: xor a call pixel jp clx cls1: ; Vertical line call vLineTest ; check if a ball hit the line ld a,(lineb) ; bottom side or a jr z,cls1a ld bc,(linel) ld a,(liney) add a,c ld (yc),a ld (stop2),a ld a,(linex) inc a inc a ld (xc),a ld a,$01 call pixel jr z,cls1c xor a ld (lineb),a cls1c: xor a call pixel cls1a: ld a,(linet) ; top side or a jp z,clx ld bc,(linel) ld a,(liney) add a,3 sub c ld (yc),a ld (stop1),a ld a,(linex) inc a inc a ld (xc),a ld a,$01 call pixel jr z,cls1b xor a ld (linet),a cls1b: xor a call pixel clx: ld bc,(linet) ; if line hasn't moved, turn it off & fill area(s) ld a,(lineb) or c jp nz,player xor a ld (linel),a ;---------= Fill area =---------- call ballx ; first, figure out what area(s) if any need to be filled ld a,(lined) or a jp nz,sideFill ;-----> up fill ld a,(liney) ld (yc),a inc a inc a ld (filly2),a ld a,(linex) inc a inc a ld (xc),a ld a,(stop1) ld (fillx1),a ld a,(stop2) ld (fillx2),a fillAreaUp: call fillPixel jr z,contFillUp ld a,(yc) ld (filly1),a jp endFillUp contFillUp: ld hl,yc dec (hl) jp fillAreaUp endFillUp: call checkQuad call nz,fillIt ;-----> down fill ld a,(liney) inc a inc a ld (filly1),a inc a inc a ld (yc),a ld a,(linex) inc a inc a ld (xc),a fillAreaDown: call fillPixel jp z,contFillDown ld a,(yc) ld (filly2),a jp endFillDown contFillDown: ld hl,yc inc (hl) jp fillAreaDown endFillDown: jp endFill ;-----> Now check sides sideFill: ;-----> Fill Left ld a,(linex) ld (xc),a inc a inc a ld (fillx2),a ld a,(liney) inc a inc a ld (yc),a ld a,(stop1) ld (filly1),a ld a,(stop2) ld (filly2),a fillLeft: call fillPixel jp z,contFillLeft ld a,(xc) ld (fillx1),a jp endFillLeft contFillLeft: ld hl,xc dec (hl) jp fillLeft endFillLeft: call checkQuad call nz,fillIt ld a,(linex) inc a inc a ld (fillx1),a inc a inc a ld (xc),a ld a,(liney) inc a inc a ld (yc),a fillRight: call fillPixel jr z,contFillRight ld a,(xc) ld (fillx2),a jp endFillRight contFillRight: ld hl,xc inc (hl) jp fillRight endFillRight: endFill: call checkQuad call nz,fillIt call ballx call player pop hl ; don't return jp skipdelay ; make it seem faster loadVars: ret fillPixel: ld a,(xc) ld de,(yc) call vector3 and (hl) ret checkQuad: ; check if a ball is in the quadrent (fillx1,filly1)-(fillx2,filly2) ; z=0 if no ball z=1 if ball ld bc,(nballs-1) ld hl,balls checkQuadLoop: ld a,(fillx1) cp (hl) jp nc,checkQuadS1 ld a,(fillx2) dec a cp (hl) jp c,checkQuadS1 inc hl ld a,(filly1) cp (hl) jp nc,checkQuadS2 ld a,(filly2) dec a cp (hl) jp c,checkQuadS2 xor a ret checkQuadS1: inc hl checkQuadS2: inc hl inc hl djnz checkQuadLoop inc a ret ;------> Fill the quadrent! ; This large routine filles the area (fillx1,filly1)-(fillx2,filly2) ; It writes entire bytes instead of just bits for speed fillIt: ; first calculate amount of area to be filled for scoring ld a,(fillx2) ld bc,(fillx1) sub c ld h,0 ld l,a ; hl=amount per line ld e,a ld d,h ; de=hl (for multiply) ld a,(filly2) ld bc,(filly1) sub c inc a sbc hl,de fillItL0: add hl,de dec a jp nz,fillItL0 ld de,(temp) add hl,de ld (temp),hl ; add to temp ld de,-3000 add hl,de ; subtract roughly 70% jp nc,fillItNoWin ; we have a winner ld de,(score) add hl,de ld de,100 add hl,de ld (score),hl ; add left over to score ld a,2 ld (lflag),a ; tell the main loop we won! fillItNoWin: ; now fill the area on the screen ld de,$0000 ld a,(fillx1) and 7 ld b,a ld a,8 sub b jp z,fillItS1 ld b,a fillItL1: scf rl d djnz fillItL1 fillItS1: ld a,(fillx2) and 7 jp z,fillItS2 ld b,a fillItL2: scf rr e djnz fillItL2 fillItS2: ld hl,(filly1) ld h,0 ld b,h ld c,l add hl,bc add hl,bc add hl,hl add hl,hl ld bc,gbuf add hl,bc ld bc,(fillx1) ld b,$00 srl c srl c srl c add hl,bc ; hl now points to where to begin writing ld a,(fillx2) srl a srl a srl a sub c ld c,a ; c=x loops ld a,d or a jp z,fillItC1 dec c bit 7,c jp z,fillItC1 inc c ld d,c ld e,c fillItC1: ld a,(filly1) ld b,a ld a,(filly2) sub b ld b,a ; b now holds the number of times to loop for ys fillItL3: push bc push hl ld a,d or a jp z,fillItF1 ld a,(hl) or d ld (hl),a ; write beginning inc hl fillItF1: ld a,c or a jp z,fillItS3 ld a,$FF fillItL4: ; write middle ld (hl),a inc hl dec c jp nz,fillItL4 fillItS3: ld a,(hl) or e ld (hl),a ; write end pop hl ld bc,12 add hl,bc pop bc djnz fillItL3 inc a ret ;---------- Check if a ball hit the line ---------- ; Two routines in one (hLineTest and vLineTest). ; This routine could be added to the one above, ; but it is aready way too big! hLineTest: ; line goes right to left ld bc,(linel) ld a,(linex) add a,c inc a ld e,a ; e holds end ld a,(linex) sub c sub 5 bit 7,a jr z,hlts0 xor a hlts0: ld d,a ; d holds start ld bc,(nballs-1) ld hl,balls ; hl holds ball offset hltl1: inc hl ; ballx - not needed yet ld a,(hl) ld c,a ld a,(liney) add a,4+1 cp c jr c,hlts2 sub 4+1+5 cp c jr nc,hlts2 dec hl ; now we need ballx ld a,(hl) inc hl cp e jr nc,hlts2 cp d jr c,hlts2 ld a,1 ld (lflag),a hlts2: inc hl inc hl djnz hltl1 ret VLineTest: ; line goes up and down ld bc,(linel) ld a,(liney) add a,c inc a ld e,a ; e holds end ld a,(liney) sub c sub 5 bit 7,a jr z,vlts0 xor a vlts0: ld d,a ; d holds start ld bc,(nballs-1) ld hl,balls ; hl holds ball offset vltl1: ld c,(hl) inc hl ld a,(linex) add a,4+1 cp c jr c,vlts2 sub 4+1+5 cp c jr nc,vlts2 ld a,(hl) ; now we need bally cp e jr nc,vlts2 cp d jr c,vlts2 ld a,1 ld (lflag),a vlts2: inc hl inc hl djnz vltl1 ret ;---------= Pixel =--------- ; input: xc,yc; a={0-test, 1-set} ; output: flag z=state (0=off, 1=on) pixel: push de ; don't destroy de di ex af,af' ; faster than a push ld de,(yc) ld a,(xc) call vector3 ld b,a ex af,af' or a ld a,b jr nz,pixelTest or (hl) ld (hl),a pixelTest: and (hl) pop de ret ;---------= Draw a sprite =--------- sprite: ld ix,(loc) ld a,(xc) ld hl,(yc) ld b,5 jp vector0 ;---------= Sprites =--------- ball: .db %01100000 ; 4*4, but the sprite routine thinks it's 5*x .db %11110000 .db %11110000 .db %01100000 hsym: .db %00000000 ; 5*5 .db %00100000 .db %11111000 .db %00100000 .db %00000000 vsym: .db %00100000 ; 5*5 .db %00100000 .db %01110000 .db %00100000 .db %00100000 ;---------= Dialog =--------- winner: .db $08,"You Won!" losser: .db $08,"You lost" name: .db $0D,"JezzBall v1.2",$00 about: .db "by Joe Wingbermuehle",$00 info1: .db "2nd - Start Game",$00 info2: .db "ALPHA - Options",$00 info3: .db "DEL - Exit",$00 info4: .db "Up/Down - Level: ",$00 info5: .db "ALPHA - Speed: ",$00 info6: .db "2nd - OK",$00 info7: .db "DEL - Cancel",$00 hscr: .db "HiScore:",$00 nhs: .db "New High Score",0 levtxt: .db "Lev: ",0 lifepic: .db %01010000 ; 4*6 .db %11111000 .db %11111000 .db %01110000 .db %00100000 ;---------= Library Table (and static variables) =--------- libraries: .db "ZLIB",0 speed: .db 2 ; SOS doesn't care about these zeros really highscore: .db 0,0 .db lib1,vec0 ; sprite .db "ZGFXL",0 slev: .db 1 .db 0,lib2,vec1 ; fastCopy .db "ZLIB",0,0,0,0,lib2,vec2 ; random .db "ZLIB",0,0,0,0,libC,vec3 ; getPixel .db "ZGFXL",0,0,0,lib1,vec4 ; largeSprite .db "ZLIB",0,0,0,0,libD,vec5 ; hiScore .db $FF ;---------= The JezzBall Graphic =--------- jezzball: .db %00001111,%00000000 .db %00011011,%00011100 .db %00000011,%00111010 .db %00000011,%00111110 .db %00000011,%00111110 .db %00000011,%00011100 .db %11000011,%00000000 .db %11000011,%00000110 .db %01111110,%00001101 .db %00111100,%00001111 .db %00000000,%00000110 .db %00001111,%11000000 .db %00011000,%01100000 .db %00011111,%11100010 .db %00011000,%00000111 .db %00011000,%01100010 .db %00001111,%11000000 .db %00000000,%00000000 .db %00000011,%11111100 .db %01000000,%00001100 .db %11100000,%00110000 .db %01000000,%11000000 .db %00000011,%00000000 .db %01100011,%11111100 .db %11010000,%00000000 .db %11110000,%11111111 .db %01100000,%00000011 .db %00000000,%00001100 .db %00010000,%00110000 .db %00111000,%11000000 .db %00010000,%11111111 .end END