;---------------------------------------- ; JezzBall 86 v1.0 ; TI-86 port by Andreas Finne with permission ; a_finne@hotmail.com ; Date: April 30th 1999 ;---------------------------------------- ; Original ZShell version by Magnus Svedin -96 ;---------------------------------------- #include "asm86.h" #include "ti86asm.inc" XPos = $C0F9 ;Current X-Position of cursors YPos = $C0FA ;Current Y-Position of cursors LastMove = $C0FB ;0=y, other=x LineOffs1 = $C0FC ;position of one edge of the line LineOffs2 = $C0FD ;position of the other edge of the line LinePos = $C0FE ;line-coord, if 0, no current line LineDir = $C0FF ;0=hor, other=ver curkey = $C100 ;key pressed clock = $C101 ;all bits toggle each loop NumBalls = $C102 ;Number of balls in play (=level) XBallDir = $C103 ;X-Direction of all balls. bit0=Ball1, 1=positive move YBallDir = $C104 ;Y-Direction of all balls. bit0=Ball1, 1=positive move XBallMove = $C105 ;X-Speed of all balls. bit0=Ball1 YBallMove = $C106 ;X-Speed of all balls. bit0=Ball1 XPosB1 = $C107 ;X-Position of ball 1 YPosB1 = $C108 ;Y-Position of ball 1 XPosB2 = $C109 ; /\ YPosB2 = $C10A ; / || \ XPosB3 = $C10B ; / || \ YPosB3 = $C10C ; || XPosB4 = $C10D ; || YPosB4 = $C10E ; || XPosB5 = $C10F ; || YPosB5 = $C110 ; || XPosB6 = $C111 ; || YPosB6 = $C112 ; || XPosB7 = $C113 ; || YPosB7 = $C114 ; || XPosB8 = $C115 ; || YPosB8 = $C116 ; || CurBall = $C117 ; Current ball (number 1-8) CurPosPtr = $C118 ; Pointer to current ball's x-pos WORD! tmp = $C11A ; Temporary variable used in varies functions. Lives = $C11B ; Lives left Speed = $C11C ; Copy of speed for ingame-usage OldContrast = $C11D ; Contrast set before jezzball ActiveControl = $C11E ; 0=speedscroll active, other constscroll active tmp2 = $C11F ; Temporary variable used when tmp is occupied RectX1 = $C120 ; Low x-coord in rectangle RectX2 = $C121 ; High x-coord in rectangle RectY1 = $C122 ; Low y-coord in rectangle RectY2 = $C123 ; High y-coord in rectangle tmp3 = $C124 ; guess what... Score = $C125 ; Current score ScoreTxt = $C127 ; ASCII-copy of score, for printing on screen (5 bytes) LevelDone = $C12C ; Indicator if level is complete, non-zero=level complete LastScore = $C12D ; Score at beginning of level (used to see if 75% is done) Move = $C12F ; Movement of cursor bits: 0=right, 1=left, 2=up, 3=down clock2 = $C130 ; same as clock but toggles every second loop RotateCount = $C131 ; Counter to make cursor-rotation happen every 8:th loop at maximum ; The ball coord points to the top left pixel of the ball. .org _asm_exec_ram nop jp Start .dw $0000 .dw Title Title: .db "JezzBall 86 v1.0",0 Start: call _runindicoff call _flushallmenus res 1,(iy+$0D) ld a, $00 ld (LevelDone), a ld (LinePos), a ld (clock), a ld (clock2), a ld a, $01 ld (NumBalls), a ld (Lives), a ld hl, $0000 ld (Score), hl ld (LastScore), hl call RandomBalls call _clrLCD ;clear screen jp StartIntro ;show intro-screen AfterIntro: call _clrLCD ;clear screen call DrawFrame ;draw frame ld hl, SpeedDB ;init speed-variable (must be done after intro) ld a, (hl) ld (Speed), a ld a, ($C008) ;change contrast and save old ld (OldContrast), a ld b, a ld hl, ContrastDB ld a, (hl) add a, b cp $1e jr c, ContrastIsOk ld a, $1e ContrastIsOk: ld ($C008), a out (2),a call DrawBalls LoopStart: ;start of main loop ld a, (clock) ;change clock xor $ff ld (clock), a cp $00 jr z, LSDontToggle ld a, (clock2) xor $ff ld (clock2), a LSDontToggle: ld a, (RotateCount) srl a ld (RotateCount), a ld a, $3e ;mask out unused keys out (1), a in a, (1) ;read key-press ld (curkey), a bit 6, a ;call key-functions jp z,LeaveGame ld a, (curkey) bit 3, a call z,MoveUp ld a, (curkey) bit 0, a call z,MoveDown ld a, (curkey) bit 1, a call z,MoveLeft ld a, (curkey) bit 2, a call z,MoveRight ld a, (curkey) bit 5, a call z,InitLine ld a, (curkey) bit 7, a call z,PrintScreen call DrawBalls ;erase balls (and cursor) before ballmoves ld a, (curkey) ;this must take place while cursor is invisible bit 4, a call z,RotateCursor call MoveCursor ;cursor must be moved while it's invisible ld a, (LinePos) ;Continue line-drawing if neccesary cp $00 call nz,DrawLine ld a, $00 ;move all existing balls ld hl, XPosB1 ld (CurPosPtr), hl LMBStl1: inc a ld (CurBall), a call MoveBall call CheckMove ld hl, (CurPosPtr) inc hl inc hl ld (CurPosPtr), hl ld a, (CurBall) ld hl, NumBalls cp (hl) jr nz, LMBStl1 call DrawBalls ;draw balls in new positions ld a, (LevelDone) ;check if level is done cp $00 jp nz,NextLevel ld a, (Lives) ;check if there's any lives left cp $00 jp z,GameOver ld a, (NumBalls) cp $09 jp z,GameDone ld a, (Speed) ;Pause-loop inc a PauseL1: ld b, $ff PauseL2: dec b jr nz, PauseL2 dec a jr nz, PauseL1 jp LoopStart ChangeDir: ;Make sure hl=XBallDir or YBallDir ld a, $01 ;find bit to change for current ball push hl ld hl, CurBall ld b, (hl) dec b jr z, CXEnd CXSt: rlca djnz CXSt CXEnd: pop hl xor (hl) ld (hl), a ret LineHit: ;called (JUMP'ed) if ball hits line call InverseScreen ld b, $ff LHPauseStl1: ld a, $a0 LHPauseStl2: dec a jr nz, LHPauseStl2 djnz LHPauseStl1 call InverseScreen ld hl, Lives ;decrease lives dec (hl) call DrawLives ld hl, LinePos ;needed later ld a, (LineDir) cp $00 ;check direction of line jr z, LHHor ld b, (hl) ;line is (was) vertical ld a, (LineOffs1) ld c, a dec c LHHStl1: ;erase line inc c call ResPixel ld a, (LineOffs2) cp c jr nz, LHHStl1 ld hl, XBallDir ; make ball bounce call ChangeDir jr LHEnd LHHor: ;line is (was) horisontal ld a, (LineOffs1) ld b, a dec b ld c, (hl) LHVStl1: inc b call ResPixel ;unerase those pixels that were black before line ld a, (LineOffs2) cp b jr nz, LHVStl1 ld hl, YBallDir ;bounce ball call ChangeDir LHEnd: ld hl, LinePos ld a, $00 ld (hl), a jp CMLineChkEnd ;continue at correct place CheckMove: ld hl, (CurPosPtr) ;Check if ball is in top of screen ld a, $01 cp (hl) jr nz, CMBNotLeft inc (hl) ;move ball away from border ld hl, XBallDir call ChangeDir ;change ball-x-direction CMBNotLeft: ld a, $5d ld hl, (CurPosPtr) cp (hl) jr nz, CMBNotRight dec (hl) ld hl, XBallDir call ChangeDir CMBNotRight: ld a, $01 ld hl, (CurPosPtr) inc hl cp (hl) jr nz, CMBNotTop inc (hl) ld hl, YBallDir call ChangeDir CMBNotTop: ld a, $3d ld hl, (CurPosPtr) inc hl cp (hl) jr nz, CMBNotBot dec (hl) ld hl, YBallDir call ChangeDir CMBNotBot: ; Start checking for pixel-hits (hits with lines) ld a, $00 ; 01 This is the bit number of each pixel in tmp. ld (tmp), a ; 32 ld hl, (CurPosPtr) ld b, (hl) inc hl ld c, (hl) call GetPixel cp $00 jr z, CMNoPix1 ld hl, tmp set 0, (hl) CMNoPix1: inc b call GetPixel cp $00 jr z, CMNoPix2 ld hl, tmp set 1, (hl) CMNoPix2: inc c call GetPixel cp $00 jr z, CMNoPix3 ld hl, tmp set 2, (hl) CMNoPix3: dec b call GetPixel cp $00 jr z, CMNoPix4 ld hl, tmp set 3, (hl) CMNoPix4: ld a, $00 ld hl, tmp cp (hl) ret z ;return if there's no hit ld a, (LinePos) ;check if there's a current line cp $00 jp z,CMLineChkEnd ;if not start checking for old-line-hits ld a, (LineDir) ;check in what direction line is cp $00 jp z,CMLineChkHorSt ld a, (LinePos) ;vertical line ld hl, (CurPosPtr) ;check if x-coord is the same as current line's cp (hl) jr z, CMLineChkVerXHit dec a cp (hl) jp nz,CMLineChkEnd CMLineChkVerXHit: ;x-coord of ball equals line's inc hl ld a, (LineOffs1) ;is y-coord less line's low y-coord? dec a dec a cp (hl) jp nc,CMLineChkEnd ;if so, there's no hit ld a, (LineOffs2) ;is y-coord more than line's high y-coord? dec a cp (hl) jp c,CMLineChkEnd ;if so there's no hit jp LineHit ;if it got all the way here there's a hit CMLineChkHorSt: ;check if ball hits current x-line ld hl, (CurPosPtr) ld a, (LineOffs1) ;check if ball is to the left of line dec a dec a cp (hl) jp nc,CMLineChkEnd ;if so, there's no hit ld a, (LineOffs2) ;check if ball is to the right of line dec a cp (hl) jp c,CMLineChkEnd ;if so, there's no hit CMLineChkHorXHit: inc hl ld a, (LinePos) ;check if y-coords match cp (hl) jp z,LineHit dec a cp (hl) jp nz,CMLineChkEnd ; othervise, start checking of old-line-hits jp LineHit CMLineChkEnd: ld hl, tmp bit 0, (hl) jr z, CMNotTop ;check if top-pixels are 1 bit 1, (hl) jr z, CMNotTop ld hl, (CurPosPtr) ;if they are, continue here inc hl ;move ball down inc (hl) ld hl, YBallDir ;change y-direction of ball call ChangeDir jp CMNotBot CMNotTop: ld hl, tmp bit 2, (hl) jr z, CMNotBot bit 3, (hl) jr z, CMNotBot ld hl, (CurPosPtr) inc hl dec (hl) ld hl, YBallDir call ChangeDir CMNotBot: ld hl, tmp bit 0, (hl) jr z, CMNotLeft bit 3, (hl) jr z, CMNotLeft ld hl, (CurPosPtr) inc (hl) ld hl, XBallDir call ChangeDir jr CMNotRight CMNotLeft: ld hl, tmp bit 1, (hl) jr z, CMNotRight bit 2, (hl) jr z, CMNotRight ld hl, (CurPosPtr) dec (hl) ld hl, XBallDir call ChangeDir CMNotRight: ret MoveBall: ld hl, (CurPosPtr) ld a, (clock) ld ix, XBallMove or (ix) ld d, a ld ix, CurBall ld b, (ix) dec b jr z, MBNSRLX1 MBChkX: srl d djnz MBChkX MBNSRLX1: ld a, d and $01 jp z,MBStartY ;if x-ball movement is 0 and clock is 0, goto y-move ld a, (XBallDir) ld d, a ld ix, CurBall ld b, (ix) dec b jr z, MBNSRLX2 MBMovX: srl d djnz MBMovX MBNSRLX2: ld a, d and $01 jr z, MBDecX inc (hl) jr MBStartY MBDecX: dec (hl) MBStartY: inc hl ld a, (clock) ld ix, YBallMove or (ix) ld d, a ld ix, CurBall ld b, (ix) dec b jr z, MBNSRLY1 MBChkY: srl d djnz MBChkY MBNSRLY1: ld a, d and $01 ret z ;if y-ball movement is 0 and clock is 0, return ld a, (YBallDir) ;check move-direction ld d, a ld ix, CurBall ld b, (ix) dec b jr z, MBNSRLY2 MBMovY: srl d djnz MBMovY MBNSRLY2: ld a, d and $01 jr z, MBDecY inc (hl) ;increase coord if positive move-direction..... ret MBDecY: dec (hl) ;decrease if negative ret RandomBalls: ld hl, XBallDir ;Randomize ball pos and movement ld b, $04 RBStl1: ;generate randoms for move and directions ld a, r ld (hl), a inc hl djnz RBStl1 ld hl, XPosB1 ;generate randoms within screen for positions ld b, $08 RBStl2: ld a, r cp $03 ;check if number is in range jr c, RBStl2 cp $5c jr nc, RBStl2 ld (hl), a inc hl RBStl3: ld a, r cp $03 jr c, RBStl3 cp $3c jr nc, RBStl3 ld (hl), a inc hl djnz RBStl2 ret DrawBalls: ld a, (XPos) ;toggle pixels under cursor ld b, a ld a, (YPos) ld c, a call ChgPixel inc b call ChgPixel dec b dec b call ChgPixel inc b inc c call ChgPixel dec c dec c call ChgPixel ld a, (LastMove) cp $00 jr nz, DBVerCursor inc c dec b dec b call ChgPixel inc b inc b inc b inc b call ChgPixel jr DBCursorDone DBVerCursor: dec c call ChgPixel inc c inc c inc c inc c call ChgPixel DBCursorDone: ld hl, XPosB1 ;toggle pixels under all balls ld a, $00 DBStl1: inc a ld (CurBall), a ld b, (hl) inc hl ld c, (hl) inc hl push hl call ChgPixel inc b call ChgPixel inc c call ChgPixel dec b call ChgPixel ld a, (CurBall) ld hl, NumBalls cp (hl) pop hl jr nz, DBStl1 ret DrawLine: ld a, (clock) ; These lines makes line increase with one pixel cp $00 ; 3/4 loops (balls moves 1 pixel/loop at most) jr nz, DLDoIt ; (default setting) ld a, (clock2) ; /\ cp $00 ; / || \ ret z ; || DLDoIt: ; || ; ld a, (clock) ; Uncomment these 3 lines if you'ld like the line ; cp $00 ; to increase by one pixel every second loop. (hard) ; ret z ; And comment out the default setting (abobve). ; If you'ld like line to increase by one pixel every loop (easy) ; then comment out both the functions abobve ld a, (LinePos) ;check if there is a current line cp $00 ret z ;if not return ld a, (LineDir) ;check direction of line cp $00 jp nz,DLVer ld a, (LinePos) ;Line was horisontal ld c, a ld a, (LineOffs1) dec a ld b, a call GetPixel ;check if the pixel to the left of line 1 is black cp $00 jr nz, DLH1Done ld a, (LineOffs1) dec a ld (LineOffs1), a ;otherwise draw another pixel call SetPixel DLH1Done: ld a, (LineOffs2) inc a ld b, a call GetPixel cp $00 jr nz, DLH2Done ld a, (LineOffs2) inc a ld (LineOffs2), a call SetPixel ret ;if second part of line was not done, return DLH2Done: ld a, (LineOffs1) ;check if first part of line is done dec a ld b, a call GetPixel cp $00 ret z ;if not, return ld a, (LineOffs1) ;check won areas abowe(however that damn word is spelled)line ld (RectX1), a ld b, a ld a, (LineOffs2) ld (RectX2), a ld a, (LinePos) dec a ld c, a ld (RectY2), a call GetPixel ;if line is just below a black area, bail out cp $00 jr nz, DLHUnderStart inc c DLHStl1: dec c call GetPixel cp $00 jr z, DLHStl1 inc c ld a, c ld (RectY1), a call CheckRect ;call procedure to check if any ball is inside rect and draw rect if not DLHUnderStart: ld a, (LinePos) ;check won areas under line inc a ld c, a ld (RectY1), a ld a, (LineOffs1) ld b, a call GetPixel cp $00 ;if line is just abobve a black area, bail out jr nz, DLHUDone dec c DLHUStl1: inc c call GetPixel cp $00 jr z, DLHUStl1 dec c ld a, c ld (RectY2), a call CheckRect ;call procedure to check if any ball is DLHUDone: ld a, $00 ;indicate that there's no active line ld (LinePos), a ret DLVer: ;Vertical line ld a, (LinePos) ld b, a ld a, (LineOffs1) ;add one pixel to top to line dec a ld c, a call GetPixel cp $00 jr nz, DLV1Done ld a, (LineOffs1) dec a ld (LineOffs1), a call SetPixel DLV1Done: ld a, (LineOffs2) ;add one pixel from bottom inc a ld c, a call GetPixel cp $00 jr nz, DLV2Done ld a, (LineOffs2) inc a ld (LineOffs2), a call SetPixel ret DLV2Done: ld a, (LineOffs1) dec a ld c, a call GetPixel cp $00 ret z ld a, (LineOffs1) ;check won areas to the left of line ld c, a ld (RectY1), a ld a, (LineOffs2) ld (RectY2), a ld a, (LinePos) dec a ld b, a ld (RectX2), a call GetPixel cp $00 jr nz, DLVUnderStart inc b DLVStl1: dec b call GetPixel cp $00 jr z, DLVStl1 inc b ld a, b ld (RectX1), a call CheckRect ;call procedure to check if any ball is within area and to draw rect if not DLVUnderStart: ld a, (LineOffs1) ld c, a ;check won areas on the right of line ld a, (LinePos) inc a ld b, a ld (RectX1), a call GetPixel cp $00 jr nz, DLVUDone dec b DLVUStl1: inc b call GetPixel ;loop until white pixel is found cp $00 jr z, DLVUStl1 dec b ld a, b ld (RectX2), a call CheckRect ;call procedure to check if any ball is DLVUDone: ld a, $00 ;finsh line off ld (LinePos), a ret InitLine: ld a, (LinePos) ;return if there already is a line cp $00 ret nz ld a, (XPos) ;check if it's black under the cursor, if so return ld b, a ;note that black=white when the cursor is drawed ld a, (YPos) ;(it is now), since it inverts what's under it ld c, a call GetPixel cp $00 ret z ld a, (LastMove) ;check direction of line ld (LineDir), a cp $00 jp z,InitLineHor ld a, (XPos) ;line will be vertical ld (LinePos), a ld a, (YPos) inc a ld (LineOffs1), a ;the line going upwards will start one pixel down dec a ;so there won't be a gap between the two lines ld (LineOffs2), a ret InitLineHor: ld a, (YPos) ld (LinePos), a ld a, (XPos) inc a ;the line going to the left will start one pixel ld (LineOffs1), a ;to the right so there won't be a gap. dec a ld (LineOffs2), a ret MoveUp: ld a, (YPos) cp $02 ret z ld ix, Move set 2, (ix) ld a, $00 ret MoveDown: ld a, (YPos) cp $3d ret z ld ix, Move set 3, (ix) ld a, $00 ret MoveLeft: ld a, (XPos) cp $02 ret z ld ix, Move set 0, (ix) ret MoveRight: ld a, (XPos) cp $5d ret z ld ix, Move set 1, (ix) ret GetPixel: ; X-value in b, Y-value in c call FindPixel and (hl) ret ;a=nonzero:pixel is 1, a=zero:pixel is 0 ChgPixel: ; X-value in b, Y-value in c call FindPixel xor (hl) ld (hl), a ret SetPixel: ; X-value in b, Y-value in c call FindPixel or (hl) ld (hl), a ret ResPixel: ; X-value in b, Y-value in c call FindPixel cpl and (hl) ld (hl), a ret DrawFrame: ld c, $00 DFStl1: ld b, $5f DFStl2: call SetPixel djnz DFStl2 call SetPixel inc c ld a, c cp $01 jr z, DFStl1 cp $02 jp z,DFGoDown cp $3f jr z, DFStl1 ;horisontal lines drawed ld b, $00 DFStl3: ld c, $02 DFStl4: call SetPixel inc c ld a, c cp $3e jr nz, DFStl4 inc b ld a, b cp $01 jr z, DFStl3 cp $02 jp z,DFGoRight cp $5f jr z, DFStl3 ld hl, ScoreText ;print score-text ld a, $67 ld (_penCol), a ld a, $01 ld (_penRow), a call _vputs ld hl, LivesText ;print lives-text ld a, $67 ld (_penCol), a ld a, $10 ld (_penRow), a call _vputs ld hl, HiScoreText ;print "HiScore" ld a, $64 ld (_penCol), a ld a, $20 ld (_penRow), a call _vputs ld hl, HiScore call LD_HL_MHL ld a, $67 ld (_penCol), a ld a, $27 ld (_penRow), a call PrintNumber ld hl, ByText ld a, $6d ld (_penCol), a ld a, $2e ld (_penRow), a call _vputs ld hl, HiName ld a, $6b ld (_penCol), a ld a, $35 ld (_penRow), a call _vputs call DrawScore call DrawLives ld a, $30 ;init values ld (XPos), a ld a, $20 ld (YPos), a ret DFGoDown: ld c, $3e jp DFStl1 DFGoRight: ld b, $5e jp DFStl3 GameOver: ld hl, HiScore call LD_HL_MHL ld de, (Score) call CP_HL_DE jp c,EnterIntls ld hl, GameOverText ld a, $04 ld (_curCol), a ld a, $03 ld (_curRow), a call _puts GOKeyLoop: call GET_KEY cp $36 jr z, GOCont cp $37 jr z, GOCont cp $09 jr nz, GOKeyLoop GOCont: call LeaveGame ret LeaveGame: ld a, (OldContrast) ;reset contrast ld ($C008), a out (2),a ld hl,ProgName ; All this stuff is to make sure the hiscore table rst 20h ; and resume stuff are stored in the variable rst 10h ex de,hl ; HL -> start of variable ld a,b ld de,SpeedDB-$D748+4 ; DE = relative offset to stuff to store (-4) add hl,de adc a,0 ; Next block if necessary ld de,SpeedDB ; DE = start of bytes to copy ld b,7 ; 7 bytes to copy RepCopy: push af push hl call $46C3 ld a,(de) ; Read ld (hl),a ; And save it in the real variable pop hl pop af call $4637 inc de djnz RepCopy set 1,(iy+$0D) call _clrScrn ret StartIntro: ld hl, IntroImage ;copy logo to video-mem ld de, $FC00 ld bc, $00C0 ldir ld bc,15*256+22 ld (_penCol),bc ld hl, IntroText1 call _vputs ld bc,23*256+20 ld (_penCol),bc call _vputs ld hl, IntroText3 ;draw scroll-bar-text ld a, $16 ld (_penCol), a ld a, $21 ld (_penRow), a call _vputs ld hl, IntroText4 ld a, $16 ld (_penCol), a ld a, $2e ld (_penRow), a call _vputs ld hl, IntroText5 ;draw "press enter..." text ld a, $53 ld (_penCol), a ld a, $3a ld (_penRow), a call _vputs ld c, $28 ;draw scroll-bars call DoScrollRect ld c, $35 call DoScrollRect call InitSpeedScroll ;get old speed-value call InitContrScroll ;get old contrast-increase ld c, $29 ;draw scrollbar-pointers call DrawSBCursor ld a, $00 ld (ActiveControl), a SIStl: ; Intro key-loop start call GET_KEY ld (tmp), a cp $37 jr nz, SINotExit ld a, ($C008) ld (OldContrast), a jp LeaveGame SINotExit: cp $38 jr nz, SINotMore call PrintScreen jr SIStl SINotMore: cp $01 jr nz, SINot1 ld a, (ActiveControl) cp $00 jr nz, SINot1 call ToggleActive ld a, $01 ld (ActiveControl), a SINot1: ld a, (tmp) cp $04 jr nz, SINot4 ld a, (ActiveControl) cp $00 jr z, SINot4 call ToggleActive ld a, $00 ld (ActiveControl), a SINot4: ld a, (tmp) cp $09 jp z,AfterIntro cp $55 jp z,AfterIntro cp $03 jr nz, SINotRight ld a, (ActiveControl) cp $00 jr nz, SIACRConst ld a, $00 call ChangeSpeed jr SINotRight SIACRConst: ld a, $02 call ChangeContr SINotRight: ld a, (tmp) cp $02 jp nz,SIStl ld a, (ActiveControl) cp $00 jr nz, SIACLConst ld a, $02 call ChangeSpeed jp SIStl SIACLConst: ld a, $00 call ChangeContr jp SIStl ChangeContr: ;a=0:decrease, a=2:increase ld (tmp2), a call InitContrScroll ;erase old ld hl, ContrastDB ld b, (hl) ld a, (tmp2) add a,b dec a ;new speed in a cp $ff ;check new value jr z, CCEnd cp $0b jr z, CCEnd ld (hl), a ;value was ok... CCEnd: call InitContrScroll ret ChangeSpeed: ;a=0:decrease, a=2:increase ld (tmp2), a call InitSpeedScroll ;erase old ld hl, SpeedDB ld b, (hl) ld a, (tmp2) add a,b dec a ;new speed in a cp $ff ;check new value jr z, CSEnd cp $51 jr z, CSEnd ld (hl), a ;value was ok... CSEnd: call InitSpeedScroll ret ToggleActive: ld c, $29 call DrawSBCursor ld c, $36 call DrawSBCursor ret DrawSBCursor: ;y-value in c ld b, $14 call ChgPixel inc c call ChgPixel inc c call ChgPixel dec c dec b call ChgPixel ld b, $6b call ChgPixel dec b call ChgPixel dec c call ChgPixel inc c inc c call ChgPixel ret InitContrScroll: ld hl, ContrastDB ld a, (hl) sla a sla a sla a add a, $17 ld b, a ld c, $36 call ChgPixel inc c call ChgPixel inc c call ChgPixel ret InitSpeedScroll: ld hl, SpeedDB ld a, $67 sub (hl) ld b, a ld c, $29 call ChgPixel inc c call ChgPixel inc c call ChgPixel ret DoScrollRect: ; y-coord in c ld a, $00 DSRLineStart: inc a ld (tmp), a ld b, $68 DSRStl1: call SetPixel dec b ld a, b cp $15 jr nz, DSRStl1 inc c inc c inc c inc c ld a, (tmp) cp $01 jr z, DSRLineStart ld a, c sub $05 ld c, a ld b, $16 call SetPixel dec c call SetPixel dec c call SetPixel ld b, $68 call SetPixel inc c call SetPixel inc c call SetPixel ret CheckRect: ;proc to check if there's any balls within rect, otherwise, draw rect ld hl, XPosB1 ld a, $00 ld b, a ; b=current ball CRStl1: ld a, (RectX1) dec a cp (hl) jr nc, CRNotInsideX ld a, (RectX2) cp (hl) jr c, CRNotInsideX inc hl ld a, (RectY1) dec a cp (hl) jr nc, CRNotInside ld a, (RectY2) cp (hl) jr c, CRNotInside ret ;If any ball inside, don't draw rectangle CRNotInsideX: inc hl CRNotInside: inc hl inc b ld a, (NumBalls) cp b jp nz,CRStl1 call DrawRect ;If all balls passed test, draw rect ret DrawScore: ld hl, (Score) ld a, $67 ld (_penCol), a ld a, $07 ld (_penRow), a call PrintNumber ret PrintNumber: ;number to print in hl, CURSOR_X and Y set ld de, ScoreTxt+4 ;buffer to store ASCII in ld b, $05 ;number of digits to print PNStl1: call UNPACK_HL ;call function to convert from number to digit add a, '0' ;convert digit to ASCII-number for digit ld (de), a ;store in ASCII-buffer dec de djnz PNStl1 ;loop 5 times ld hl, ScoreTxt ld b, $05 res 3, (iy+5) ;overwrite current screen with menu-texts call _vputsn ;print it to screen ret DrawLives: ld a, (Lives) add a, '0' ld (tmp), a ld hl, tmp ld a, $6f ld (_penCol), a ld a, $16 ld (_penRow), a ld b, $01 res 3, (iy+5) ;overwrite current screen with menu-texts call _vputsn ret PrintScreen: res graphdraw,(iy+graphflags) ;Resets flag so picture can bee seen ld hl,$FC00 ld de,_plotSScreen ld bc,1024 ldir ret CheckArea: ld hl, (LastScore) ;check if 4128 points has been earned at this level ld de, $1020 add hl, de ld de, (Score) call CP_HL_DE ret nc ld a, $01 ld (LevelDone), a ret NextLevel: ld a, $03 ;print "Level Done!" ld (_curCol), a ld a, $03 ld (_curRow), a ld hl, LevelText call _puts ld a, $00 ld (LevelDone), a ld hl, (Score) ;increase score by 1000 for each life left ld a, (Lives) ld b, a ld de, $03e8 NLStl1: add hl, de djnz NLStl1 ld (Score), hl ld a, (NumBalls) ;increase number of balls inc a ld (NumBalls), a ld (Lives), a ;set up number of new lives ld a, (Speed) ;decrease delay since it's slower when there's more balls sub $03 jr c, NLAlreadyMax ld (Speed), a NLAlreadyMax: ld b, $ff ;pause loop NLPauseStl1: ld c, $ff NLPauseStl2: push de dec c pop de jr nz, NLPauseStl2 dec b jr nz, NLPauseStl1 call _clrLCD call DrawFrame call RandomBalls ld hl, (Score) ld (LastScore), hl call DrawBalls jp LoopStart EnterIntls: ld a, $02 ;print "New HiScore" ld (_curCol), a ld a, $02 ld (_curRow), a ld hl, NewHiScoreText call _puts ld a, $01 ;print "Enter Initials" ld (_curCol), a ld a, $03 ld (_curRow), a ld hl, EnterIntlsText call _puts ld a, $06 ;print @@@ ld (_curCol), a ld a, $04 ld (_curRow), a ld a, $41 call _putc call _putc call _putc ld a, $06 ld (_curCol), a ld b, $41 ld c, $00 EIKeyLoop: push bc call GET_KEY pop bc cp $04 jr nz, EINotUp dec b ld a, b cp $40 jr nz, EIUpNotInc inc b inc a EIUpNotInc: push bc call _putc pop bc jr EIDecCursor EINotUp: cp $01 jr nz, EINotDown inc b ld a, b cp $5b jr nz, EIDownNotInc dec a dec b EIDownNotInc: push bc call _putc pop bc jr EIDecCursor EINotDown: cp $36 jr nz, EIKeyLoop ld hl, HiName ;update hiscore name ld a, $00 cp c jr z, EIFirstIndex EINameIndex: inc hl dec c jr nz, EINameIndex ld c, $01 EIFirstIndex: inc c ld (hl), b ld b, $41 ;print char and move cursor ld a, (_curCol) inc a ld (_curCol), a cp $09 jp nz,EIKeyLoop ld ix, Score ;update hiscore ld hl, HiScore ld a, (ix) ld (hl), a inc ix inc hl ld a, (ix) ld (hl), a jp GOCont EIDecCursor: ld a, (_curCol) dec a ld (_curCol), a jp EIKeyLoop InverseScreen: ld hl, $FC00 ld de, $0000 ISStl1: ld a, (hl) xor $ff ld (hl), a inc hl call CP_HL_DE jr nz, ISStl1 ret GameDone: ld hl, GameDoneText ld a, $00 ld (_curCol), a ld a, $01 ld (_curRow), a call _puts jp GameOver DrawRect: ld a, (RectX1) ;first update score ld b, a ld a, (RectX2) sub b inc a ld c, a ld b, $00 push bc ;bc=delta x ld a, (RectY1) ld b, a ld a, (RectY2) sub b inc a ;a=delta y ld hl, (Score) pop bc DRScoreStl1: add hl, bc dec a jr nz, DRScoreStl1 ;add delta x for each y-line ld (Score), hl call DrawScore ;update score on screen call CheckArea ;check if level is done ;here is where the actual drawing takes place ld a, (RectX1) ;tmp=delta x -1 ld b, a ld a, (RectX2) sub b ld (tmp), a ld a, (RectY1) ;tmp2=delta y ld c, a ld a, (RectY2) sub c inc a ld (tmp2), a ld a, (RectX1) ld b, a ;load top-left byte in a ld a, $00 ld ix, tmp cp (ix) jp z,DROnePixel call FindPixel ld ix, tmp DRStl1: ;fill top-bits in a (or as many as specified in tmp) ld b, a srl a or b dec (ix) jr z, DRDone1 bit 0, a jr z, DRStl1 DRDone1: ;or the bits onto the screen ld c, a ld (tmp3), hl ld a, (tmp2) ld b, a ld de, $10 DRStl2: ld a, (hl) or c ld (hl), a add hl, de djnz DRStl2 ld a, (tmp) ;return if no columns left to fill cp $00 ret z DR8bitStl1: ld hl, (tmp3) ;move hl-pointer to top-line, next 8-bit col inc hl ld (tmp3), hl ld a, (tmp) cp $08 ;check if 8-cols are left to set jr c, DR8bitDone sub $08 ld (tmp), a ;decrease x-cols-left with 8 cols ld a, (tmp2) ld b, a DR8bitStl2: ;fill it up! ld (hl), $ff add hl, de djnz DR8bitStl2 jr DR8bitStl1 DR8bitDone: ld a, (tmp) ;fill last pixels cp $00 ret z ld c, $80 DRFinalStl1: ;start loop of pixels to fill ld a, (tmp) dec a jr z, DRFinalDone ld (tmp), a ld a, c srl a or c ld c, a jr DRFinalStl1 DRFinalDone: ;or the bits onto the screen ld a, (tmp2) ld b, a ld de, $10 DRFinalStl2: ld a, (hl) or c ld (hl), a add hl, de djnz DRFinalStl2 ;this is the end of the draw-code ld a, (RectX2) ;now check if the damn bug has occured ld b, a ld a, (RectY1) ld c, a call GetPixel cp $00 ret nz ;if not return DRFixBugStl1: ;if it has, fill the last line call SetPixel inc c ld a, (RectY2) cp c jr nc, DRFixBugStl1 ret DROnePixel: ;also part of drawrect call FindPixel jp DRDone1 MoveCursor: ld ix, Move bit 0, (ix) jr z, MCNotLeft ld a, (XPos) dec a ld (LastMove), a ld (XPos), a res 0, (ix) MCNotLeft: bit 1, (ix) jr z, MCNotRight ld a, (XPos) inc a ld (LastMove), a ld (XPos), a res 1, (ix) MCNotRight: bit 2, (ix) jr z, MCNotUp ld a, (YPos) dec a ld (YPos), a res 2, (ix) ld a, $00 ld (LastMove), a MCNotUp: bit 3, (ix) ret z ld a, (YPos) inc a ld (YPos), a res 3, (ix) ld a, $00 ld (LastMove), a ret RotateCursor: ld a, (RotateCount) cp $00 ret nz ld a, $ff ld (RotateCount), a ld a, (LastMove) cp $00 jr z, RCIsZero ld a, $00 ld (LastMove), a ret RCIsZero: ld a, $01 ld (LastMove), a ret ;-------------------------------------------------------------------- ; The Eble-Yopp-Yopp-Eble-Eble-Eble-Yopp Fast FindPixel Routine :) ; 36 bytes / 121 t-states not counting ret or possible push/pop of BC ;-------------------------------------------------------------------- ; Input: D = y ; E = x ; Output: HL= address of byte in video memory ; A = bitmask (bit corresponding to pixel is set) ; C is modified ; ; +-----------+ ; |(0,0) | <- Screen layout ; | | ; | (127,63)| ; +-----------+ ; ;-------------------------------------------------------------------- FindPixel: push bc ld e,b ld d,c ld hl,FP_Bits ld a,e and $07 ; a = bit offset add a,l ld l,a adc a,h sub l ld h,a ld c,(hl) ; c = bitmask for (hl) ;48 t-states up to this point ld hl,FP_RLD ld (hl),d ld a,e ; a = x/8 (byte offset within row) rrca rrca rrca rld or $FC ld l,(hl) ld h,a ; hl -> byte in vid mem ld a,c ; now a = bitmask for (hl) ;121 t-states up to this point pop bc ret FP_RLD: .db $00 FP_Bits: .db $80,$40,$20,$10,$08,$04,$02,$01 IntroImage: .db %00000000,%00110011,%11111110,%01111111,%10111111,%11011111,%11100000,%00111000,%00110000,%00001100,%00000000,%00011110,%00001111,%10000000,%00000000,%00000000 .db %00000000,%00110011,%11111110,%01111111,%10111111,%11011111,%11110000,%00111000,%00110000,%00001100,%00000000,%00111111,%00011111,%11000000,%00000000,%00000000 .db %00000000,%00110011,%00000000,%00000011,%00000001,%10011000,%00110000,%01101100,%00110000,%00001100,%00000000,%01100001,%10011000,%11000000,%00000000,%00000000 .db %00000000,%00110011,%00000000,%00000110,%00000011,%00011000,%00110000,%01101100,%00110000,%00001100,%00000000,%01100001,%10110000,%00000000,%00000000,%00000000 .db %00000000,%00110011,%00000000,%00001110,%00000111,%00011000,%00110000,%01101100,%00110000,%00001100,%00000000,%01100001,%10110111,%00000000,%00000000,%00000000 .db %00000000,%00110011,%11111110,%00001100,%00000110,%00011111,%11100000,%11000110,%00110000,%00001100,%00000000,%00111111,%00111111,%10000000,%00000000,%00000000 .db %00000000,%00110011,%11111110,%00011000,%00001100,%00011111,%11110000,%11000110,%00110000,%00001100,%00000000,%00111111,%00111001,%11000000,%00001000,%01100000 .db %00000000,%00110011,%00000000,%00111000,%00011100,%00011000,%00111000,%11111110,%00110000,%00001100,%00000000,%01100001,%10110000,%11000000,%00011000,%10010000 .db %00001100,%00110011,%00000000,%00110000,%00011000,%00011000,%00011001,%11111111,%00110000,%00001100,%00000000,%01100001,%10110000,%11000001,%01001000,%10010000 .db %00001110,%01110011,%00000000,%01100000,%00110000,%00011000,%00011001,%10000011,%00110000,%00001100,%00000000,%01100001,%10011000,%11000001,%01001000,%10010000 .db %00000111,%11100011,%11111110,%11111111,%11111111,%11011111,%11110001,%10000011,%00111111,%11001111,%11110000,%00111111,%00011111,%10000000,%10001000,%10010000 .db %00000011,%11000011,%11111110,%11111111,%11111111,%11011111,%11100011,%00000001,%10111111,%11001111,%11110000,%00011110,%00001111,%00000000,%10001010,%01100000 SpeedDB: .db $20 ContrastDB: .db $05 HiScore: .db $10, $27 HiName: .db "JOE", 0 IntroText1: .db "Original by Magnus Svedin",0 IntroText2: .db "TI-86 port by Andreas Finne",0 IntroText3: .db "Speed",0 IntroText4: .db "Contrast increase",0 IntroText5: .db "Press Enter...",0 GameDoneText: .db "That's all folks", 0 ScoreText: .db "Score", 0 LivesText: .db "Lives", 0 HiScoreText: .db "HiScore", 0 ByText: .db "By:", 0 LevelText: .db "Level done!", 0 GameOverText: .db "GAME OVER", 0 NewHiScoreText: .db "New HiScore!", 0 EnterIntlsText: .db "Enter initials", 0 ProgName: .db $12,8,"jezzball" .end