; 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