;KOLLUMS source for version 2.0 ; ;Here is the source code for KOLLUMS v2.0 ;I'm distributing it for all those people who want to learn assembly for the 86 ;I've commented it very much, although I got kinda sick of commenting late at night :( ; ; ;Some of the stuff I added in v2.0 I didn't comment, too bad ; ;Please learn something from it, and if you do, give me some credit. ; ;mail me with anything!! --> bailela@charlie.cns.iit.edu ; ;This source is Copyright (C) 1997 Alan Bailey. Please don't redistribute any modified ;version of this program. You can modify all you want, just don't redistribute. Feel ;free to cut and paste something, but give me some credit. If you see anything wrong, ;or see something I could do better, mail me and tell me. ; ;If you want to recompile it, get Asm86 from ticalc.org at ;http://www.ticalc.org/pub/dos/asm/asm86.zip ;There's some stuff in here that's specific to that ; ;Alan Bailey ;bailela@charlie.cns.iit.edu ;http://www.iit.edu/~bailela/ <--- check my page out, it's new ;IRC: Abalone on #calc-ti on EFnet #include "asm86.h" ;I use Asm86 to compile, so I include this #include "ti86asm.inc" ;this is TI's include file .org _asm_exec_ram ;starting point for all asm progs, $D748 ; XCoord -> ; ---------------- ; |(0,0) (15,0)| ; | | Y 16*7=112 bytes ; | | C ; | | o ; | | o ; | | r ; |(0,7) (15,7)| d ; | info line | \/ ; ---------------- Start: call _clrLCD ;clear the screen! ld a,%01010101 ;this is the bitmap for the top seven lines of the intro ld b,7 ;we have seven lines ld hl,$FC00 ;this is the first spot we want to write to Graphxloop: push bc ;save the counter of lines ld b,16 ;make a new counter of bytes in the line (16) Graphxloop2: ld (hl),a ;put the bitmap in inc hl ;increment to the next byte on screen djnz Graphxloop2 ;and jump back until line is finished cpl ;this is equal to , to change the bitmap pop bc ;get the old counter back djnz Graphxloop ;and keep going until all seven lines done ;now we display some words ld bc,$0501 ;now we display the words, $0501 are first coordinates ld (_curRow),bc ;load them in, _curRow gets $01, _curCol gets $05 ld hl,TitleStr ;this is absolute address of string "KOLLUMS 1.0" call _puts ;put it out on screen ld bc,$0303 ;next coordinates ld (_curRow),bc ;load them in ;ld hl,Author ;this string is right after the previous one, so hl set call _puts ;put it out ld bc,$220F ld (_penCol),bc ;ld hl,Email call _vputs ;this is a variable-width put string ld bc,$3103 ld (_penCol),bc ;ld hl,Difficulty call _vputs call DispDiff ;this routine displays the boxes (difficulty) ld hl,ResumeStr ld bc,$3918 ld (_penCol),bc call _vputs FirstKeyCheck: halt ;saves valuable battery power when waiting call Randomize ;Randomize the variables call GET_KEY ;gets the recent key pressed cp K_EXIT ;compare it to exit jr z,TimetoLeave ;if it's exit, go to TimetoLeave cp K_RIGHT ;and similar jp z,MoveLevelRight cp K_LEFT jp z,MoveLevelLeft cp K_ENTER jp z,StartAction cp K_SECOND jp z,StartAction cp K_F1 jp z,ResumePaused jr FirstKeyCheck ;goes back to check other keys TimetoLeave: call LoadData call _clrLCD ;and clear the screen one last time ret ;and leave now that the scores are saved ResumePaused: ld a,(SavedGame) or a jp z,FirstKeyCheck ;no saved game call _clrLCD call PutScreen ;Puts out any blocks in the BlockMem ld hl,$3803 ;coords for LevelDiff ld (_penCol),hl ;loads them ld a,(LevelDiff) ;gets LevelDiff add a,'0' ;add '0' to make it ASCII char ld b,1 ;number of chars to display ld hl,StringPlace ;place to store char to display ld (hl),a ;puts it in call _vputsn ;displays 1 char pointed to by hl call UpdateScore ;Puts score call UpdateLevel ;Puts level call DispHigh ;Puts high score call DrawCurrent ;and Draws the current three blocks jp keycheck ;----------------------------------- ;This routine moves the difficulty level to the right ;from the intro screen, jumps back to FirstKeyCheck MoveLevelRight: ld a,(LevelDiff) ;gets the LevelDifficulty cp 8 ;the highest it can be jp z,FirstKeyCheck ;if it's the highest, go back now inc a ;or increment it! ld (LevelDiff),a ;loads it back ld a,1 ;the randoms might be upset by switching the difficulty ld (Rand1),a ;so this restarts all randoms ld (Rand2),a ld (Rand3),a call DispDiff ;and display the difficulty boxes again jp FirstKeyCheck ;jump back to key check ;----------------------------------- ;This routine moves the difficulty level to the left ;from the intro screen, jumps back to FirstKeyCheck MoveLevelLeft: ;this just like MoveLevelRight ld a,(LevelDiff) cp 3 ;the lowest point jp z,FirstKeyCheck dec a ld (LevelDiff),a ld a,1 ld (Rand1),a ld (Rand2),a ld (Rand3),a call DispDiff jp FirstKeyCheck ;----------------------------------- ;This routine displays the boxes to represent ;the difficulty. Returns when it is done DispDiff: ld a,(LevelDiff) ;gets the LevelDifficulty = number of boxes ld b,a ;put in b as a counter ld a,$01 ;this is the first block bitmap we want to display ld de,$0706 ;xy position for first block DispDiff2: push bc ;saves bc (counter) push af ;saves af (block description) push de ;saves de (xy coords) push de ;no doens't save de, puts de in bc pop bc ;cause we pushed it, now it's popped into a differnet rp call DrawBlock ;and call DrawBlock with a containing block, bc has coords pop de ;gets the saved coords inc d ;and increment the xcoord pop af ;gets the saved block type inc a ;and moves to the next block pop bc ;gets the saved counter djnz DispDiff2 ;and does all blocks equal to LevelDiff ld a,$00 ;these next four lines put a blank block at the end push de ;just in case pop bc call DrawBlock ret ;and go back where you came from ;--------------------------- ;This part called when all done selecting level ;and enter or second has been pressed StartAction: sub a ;make a zero, literally subtract a from a ld (SpeedLevel),a ;SpeedLevel is now zero ld hl,BlockMem ld de,BlockMem+1 ld (hl),0 ld bc,111 ldir ld hl,$0660 ;This is the first DelayTimer value ld (DelayTimer),hl ;load it in to variable ld hl,$0000 ld (Score),hl call _clrLCD call MakeNewSet ;make new set of three blocks call PutScreen ;Puts out any blocks in the BlockMem ld hl,$3803 ;coords for LevelDiff ld (_penCol),hl ;loads them ld a,(LevelDiff) ;gets LevelDiff add a,'0' ;add '0' to make it ASCII char ld b,1 ;number of chars to display ld hl,StringPlace ;place to store char to display ld (hl),a ;puts it in call _vputsn ;displays 1 char pointed to by hl call UpdateScore ;Puts score call UpdateLevel ;Puts level call DispHigh ;Puts high score call DrawCurrent ;and Draws the current three blocks keycheck: call Randomize ;called at random time to make it random call GET_KEY ;same kind of keyloop cp K_UP jp z,MoveLeft cp K_DOWN jp z,MoveRight cp K_SECOND jp z,RotateBlocks cp K_EXIT jp z,GameAllDone cp K_MORE jp z,PauseGame cp K_F1 jr z,SuspendGame cp K_LEFT call z,MoveDown ;this is a call because MoveDown is a function ;will return here, no problem ld hl,(DelayTimer) ;gets the time delayed dec hl ;decrements it ld (DelayTimer),hl ;and load it back ld a,l ;puts l into a or h ;ors h with l, if _anything_ is set, it will not be zero jr nz,keycheck ;so if not zero, jr keycheck call MoveDown ;Time all decremented, move it down a notch ld a,(CurrFinished) ;CurrFinished is changed in MoveDown or a jp nz,FinishedSet ;if it is not zero, means finished, and goes to FinishedSet ld a,(SpeedLevel) ;these next eight lines make DelayTimer from SpeedLevel rlca ;rotate left, so number is multiplied by 2 ld c,a ;puts that offset into bc ld b,0 ;like that ld hl,TimerTable ;now here's the table we want to analyze add hl,bc ;include the offset call LD_HL_MHL ;and get the value pointed to by hl in TimerTable ld (DelayTimer),hl ;that's the current DelayTimer jr keycheck ;and jump back to check the keys SuspendGame: ld a,1 ld (SavedGame),a call LoadData call _clrLCD ret ;------------------------- ;Simple routine to follow when MORE is pressed PauseGame: ; halt ;saves some time and battery power call GET_KEY ;gets key cp 0 ;if anything, jp nz,keycheck ;go back to keycheck jr PauseGame ;or stay in this loop ;----------------------------------- ;Routine to move the blocks around in their set RotateBlocks: ld hl,CurrTop ;address of the top block ld b,(hl) ;put in b temporarily inc hl ;go to the middle block ld a,(hl) ;put the middle block in a ld (hl),b ;and the top block in the middle block inc hl ;go to the lower block ld b,(hl) ;put the lower block in b ld (hl),a ;put the middle block in the lower block ld hl,CurrTop ;get top block again ld (hl),b ;and put lower block in top block call DrawCurrent ;redraw it jp keycheck ;and jump back ;---------------------- ;Routine to move the set to the left ;erases it and redraws it MoveLeft: ld hl,(YCoord) ;gets the y coord and x coord ld a,l ;puts y coord in a or a ;checks if zero, (at left side jp z,keycheck ;if at left side, go back now push hl ;puts hl pop bc ;in bc dec c ;dec y coord call GetBlock ;get value of block and address on left side of three inc hl ;next up block add a,(hl) ;get value inc hl ;next one add a,(hl) ;get value jp nz,keycheck ;basically, just check if any blocks to the left are occupied ld hl,(YCoord) ;gets block at bottome push hl ;puts hl pop bc ;in bc sub a ;makes it a blank block push bc ;saves coords for next run through call DrawBlock ;deltes block by putting blanks there pop bc ;gets saved coords inc b ;ready to erase next block sub a push bc call DrawBlock pop bc inc b sub a call DrawBlock ;all three blocks deleted ld hl,(YCoord) ;get coords dec l ;now we decrement it ld (YCoord),hl ;and load it back call DrawCurrent ;and draw it, how fun! jp keycheck ;and go back to checking keys MoveRight: ;just like MoveLeft, look above, it's very similar ld hl,(YCoord) ld a,l cp 6 jp z,keycheck push hl pop bc inc c call GetBlock inc hl add a,(hl) inc hl add a,(hl) jp nz,keycheck ld hl,(YCoord) push hl pop bc sub a push bc call DrawBlock pop bc inc b sub a push bc call DrawBlock pop bc inc b sub a call DrawBlock ld hl,(YCoord) inc l ld (YCoord),hl call DrawCurrent jp keycheck ;------------------- ;This displays the high score for that level DispHigh: ld hl,$3810 ;place to put high score ld (_penCol),hl ;put it in ld hl,HighStr ;get string High: call _vputs ;put that little string ld a,(LevelDiff) cp 3 jr z,DispHigh3 ;if level 3 cp 4 jr z,DispHigh4 ;if level 4 cp 5 jr z,DispHigh5 ;if level 5 cp 6 jr z,DispHigh6 cp 7 jr z,DispHigh7 jr DispHigh8 ;defaults to level 8 if not anything else DispHigh3: ;gets address for High3 ld hl,High3 jr DispHigh2 DispHigh4: ld hl,High4 ;gets address for High4 jr DispHigh2 DispHigh5: ld hl,High5 jr DispHigh2 DispHigh6: ld hl,High6 jr DispHigh2 DispHigh7: ld hl,High7 jr DispHigh2 DispHigh8: ld hl,High8 jr DispHigh2 DispHigh2: ;now it works on the information push hl call LD_HL_MHL ;gets the high score from mem ld de,StringPlace+4 ;sets de for putting score ld b,5 ;5 characters in score UpdateHigh: call UNPACK_HL ;divides hl by 10 and has the remainder in a, add a,'0' ;make digit ascii ld (de),a ;load it into stringplace, ready for displaying dec de ;next spot to load djnz UpdateHigh ;and go to UpdateHigh for next 4 characters ld hl,StringPlace ;now it contains the score, asciiized and zero-terminated call _vputs ;display the score ld a,(_penCol) ;get the Col from mem ld b,4 ;increase it add a,b ;like that ld (_penCol),a ;and load it back pop hl ;this is the address to high score inc hl ;right after it is Initials, so this increments to that inc hl call _vputs ;and put the Initials of High Scorer ret ;leave ;----------------------- ;randomizes the varialbes ;this is called many times from the keyloops ;This code is mostly (C) 1996 Mel Tsai from Columns3 ;All commments are Mel Tsai's Randomize: ld a, (LevelDiff) ; 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, (Rand1) ; 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 (Rand1), a ret RANDINC_1: ld a, 1 ld (Rand1), a ld a, (Rand2) inc a cp b jr z, RANDINC_2 ld (Rand2), a ret RANDINC_2: ld a, 1 ld (Rand2), a ld a, (Rand3) inc a cp b jr z, RANDINC_3 ld (Rand3), a ret RANDINC_3: ld a, 1 ld (Rand3), a ret ;---------------------------------------------------------------- ;---------------------------------------------------------------- ;Huge routine to check all directions for rows of common blocks ;Runs through the Horizontal, then Vert, then the two diagonals ;---------------------------------------------------------------- BlockTestTime: sub a ld (TotalBlockCount),a ;----------- Horiz: ld hl,BlockMem ;first spot of startingblock ld b,7 ;7 columns Horiz2: push bc ;save counter push hl ;save address of starting block ld e,16 ;16 in a line ld a,1 ;the difference between each block is one byte ld (BlockDiff),a ;like that call TestLine ;now we test that line, which tags them pop hl ;get address back ld de,$0010 ;add 16 to get to the next line add hl,de ;like that pop bc ;now we get the counter back for all seven djnz Horiz2 ;----------- Vert: ld hl,BlockMem ;first spot of startingblock ld b,16 ;opposite of Horiz, so 16 columns Vert2: push bc ;save counter push hl ld e,7 ;number in line ld a,$0010 ;this is the difference now in the other direction ld (BlockDiff),a ;load it call TestLine ;Test that line pop hl ;get back startingblock inc hl ;go to next startingblock pop bc ;for all 16 times djnz Vert2 ;checked here ;----------- Diag1: ld hl,BlockMem ;starting position for diagonal ld b,10 ;10 diagonals of length 7 Diag12: push bc ;save push hl ;save ld e,7 ;7 blocks in these 10 diagonals ld a,$0011 ;this means difference is one line ($10) + one block ($01) ld (BlockDiff),a ;load it into BlockDiff call TestLine ;and test pop hl inc hl ;inc to get to next starting block of diagonal pop bc djnz Diag12 ;these next sets of three lines test the little diagonals ld hl,BlockMem+16 ;diagonal of length 6 starting at that block ld e,6 call TestLine ;Test it! - BlockDiff is always the same ld hl,BlockMem+32 ld e,5 call TestLine ld hl,BlockMem+48 ld e,4 call TestLine ld hl,BlockMem+64 ld e,3 call TestLine ld hl,BlockMem+10 ld e,6 call TestLine ld hl,BlockMem+11 ld e,5 call TestLine ld hl,BlockMem+12 ld e,4 call TestLine ld hl,BlockMem+13 ld e,3 call TestLine ld hl,BlockMem+14 call TestLine ;------------ Diag2: ;refer to Diag1, this is very similar ld hl,BlockMem+6 ld b,10 Diag22: push bc push hl ld e,7 ld a,$000F ;this is the only difference, means one less block than a line ld (BlockDiff),a call TestLine pop hl inc hl pop bc djnz Diag22 ;this next have the same format, but different numbers ld hl,BlockMem+2 ld e,3 call TestLine ld hl,BlockMem+3 ld e,4 call TestLine ld hl,BlockMem+4 ld e,5 call TestLine ld hl,BlockMem+5 ld e,6 call TestLine ld hl,BlockMem+16+15 ld e,6 call TestLine ld hl,BlockMem+32+15 ld e,5 call TestLine ld hl,BlockMem+48+15 ld e,4 call TestLine ld hl,BlockMem+64+15 ld e,3 call TestLine ret ;returns with all common blocks tagged ( bit 7 set) ;---------------------------------------- ;Call this with first address in hl, Difference between blocks in (BlockDiff) ;total blocks in line in e ;---------------------------------------- ;During this routine, d=block count ; e=blocks to check, like a counter ; a=temporary variable ; hl=address of block being checked ; c=block to test against ; b=counter sometimes, bc temporary variable sometimes ;---------------------------------------- TestLine: ld d,0 ;d starts at zero ld a,e ;load e into a to test against or a ;cp 0 ret z ;if e is zero, blocks in line all checked ld a,(hl) ;gets block at address and %01111111 ;mask out top bit, tagged block possibly jr z,SkipZeroes ;if it's a zero, skip it, doesn't matter ld (StartBlock),hl ;that used as the first block in a possible series ld c,a ;c has the block to test against TestLine2: ld a,e ;check against e again or a jr z,TestLine3 ;if blocks all done, go here to see if you have three or more inc d ;block count so far push bc ;save bc, variables limited ld a,(BlockDiff) ;get difference between blocks in line ld c,a ;put it in bc ld b,0 ;like that add hl,bc ;and get the offset added to the previous block pop bc ;get bc back dec e ;we're done with one block, so decrement total ld a,(hl) ;get the next block and %01111111 ;mask out top bit, tagged block xor c ;check block with block being tested jr z,TestLine2 ;if same, keep going, we might have a line TestLine3: ;this checks if we have 3, if so, tags them ld a,d ;gets block count in common series inc a ;ease testing and %11111100 ;if it's 1 or 2, it won't count jr z,TestLine ;so if not 3 or more, go back and continue checking that line ld b,d ;blocks in common are used as counter here ld hl,(StartBlock) ;the starting block in the series TestLine4: set 7,(hl) ;tag it push bc ;save bc ld a,(BlockDiff) ;add the blockdifference again ld c,a ld b,0 add hl,bc ;like that pop bc ;and get bc back ld a,(TotalBlockCount) ;counts total blocks tagged, used as score inc a ;increment it because one block tagged ld (TotalBlockCount),a ;save it djnz TestLine4 ;continue to tag all in the set jr TestLine ;continue with the next block in the line SkipZeroes: push bc ;save bc! ld a,(BlockDiff) ;add block diff again to get at next block ld c,a ld b,0 add hl,bc pop bc ;get bc back dec e ;dec because one block skipped jr TestLine ;anc continue teseting ;----------------------------- ;This routine erases all blocks that ;are tagged (bit 7 set). It just erases them, doens't remove the tags DeleteBlocks: ld hl,BlockMem ;the first block ld de,$0000 ;first coords, (0,0) ld b,7 ;there are 7 rows DeleteBlocks2: push bc ;save that counter ld b,16 ;there are 16 rows DeleteBlocks3: push bc ;save that counter push de ;this puts de pop bc ;into bc for the routine DrawBlock bit 7,(hl) ;test for the tag jr z,DeleteBlocks4 ;if it is zero,( not tagged), then go here sub a ;blank block call DrawBlock ;this draws a blank block (sub a) DeleteBlocks4: inc hl ;this moves up the address inc d ;inc x coord pop bc ;get first counter djnz DeleteBlocks3 ;go back if not done with the row yet ld d,0 ;or... now we set the x coord back to zero inc e ;and inc the y coord pop bc ;retrieve this counter djnz DeleteBlocks2 ;and do the loop again ret ;get out of this function ;-------------- ;this moves all the blocks down that are tagged and have been ;erased from the screen DropDown: ld hl,BlockMem ;first block... ld b,7 ;7 rows DropDown2: push bc ;save the counter ld bc,15 ;this is used as amount to move down, for the ldir DropDown3: bit 7,(hl) ;test the tag jr z,DropDown4 ;if it's not tagged, leave this place, or continue on... push hl ;this puts hl (the tagged block) pop de ;into de for the ldir inc hl ;goes to the next block for the ldir push bc ;save bc (will be changed by ldir) push hl ;save hl (will be cahnged by ldir) ldir ;this ldir moves all the blocks above the tagged block down ;one block, therefore erasing the tagged block pop hl ;retrieve hl dec hl ;and dec it because we had to inc it before pop bc ;retrieve bc, (saved from the ldir) add hl,bc ;we getting to the last block in the line ld (hl),$00 ;blank out the top block now that we've moved something or a ;reset carry flag sbc hl,bc ;gets back to the block we were on jr DropDown3 ;we're going to have to test teh same block again, because we ;just moved a different block into that position DropDown4: ;or... if not tagged inc hl ;move up to the next block dec bc ;moved up, so the blocks above it is decreased ld a,c ;check if c is zero yet or b ;by testing it against b (always zero) jr nz,DropDown3 ;if stuff still to do, go here inc hl ;go to the next line because at the end of the previous line pop bc ;the huge outer loop for each column djnz DropDown2 ;go if still more rows to do ret ;leave this friggin routine ;------------------ ;called when it is detected that the set of three have hit the bottom FinishedSet: sub a ;make a zero ld (CurrFinished),a ;clear the indicator that shows whether set is done ld hl,(YCoord) ;we get the coords push hl pop bc ;and get them into bc call GetBlock ;so we can Get the address of the Block ld a,(CurrBot) ;hl is the address of the block ld (hl),a ;so load the block into the memory inc hl ;next block will just be one above ld a,(CurrMid) ;now we do the same with the middle one ld (hl),a ;there inc hl ld a,(CurrTop) ld (hl),a ;and the top one FinishedSet2: call BlockTestTime ;now that the mem is set, test all the blocks for matches call DeleteBlocks ;erase those blocks that are tagged by BlockTestTime ld de,$DFFF ;this is a small pause to make it look realistic FinishedSet3: dec de ;lower counter ld a,d ;or d or e ;with e jr nz,FinishedSet3 ;if something still there, continue with loop call DropDown ;now after delay, dropdown the blocks in mem call PutScreen ;and display the whole new screen ld a,(TotalBlockCount) ;this checks if there are more blocks to delete ld hl,(Score) ;add blocks to score ld c,a ;get a into bc ld b,0 ;like that add hl,bc ;add it to the score ld (Score),hl ;and put it back, yaah or a ;a still has the blocks deleted jr z,FinishedSet4 ;if it is zero (no blocks were deleted), jump to here ld de,$6FFF ;this goes back to check for more blocks after a pause lilloop: dec de ;this is the delay loop all over again ld a,d or e jr nz,lilloop jr FinishedSet2 ;and go back to check for more blocks FinishedSet4: ;all done, now last stuff ld hl,(Score) ;get score rl l ;these two commands rotate hl left once rl h ;you need to remember to grab the carry ld a,h ;we only want the info in h to test if 128 or more bit 3,a ;if there is more than 1024 points jr nz,GameAllDone ;go to GameAllDone ld (SpeedLevel),a ;the upper portion defines the speed rlca ;now we use the level to get the value for DelayTimer ld c,a ;put speed*2 into bc ld b,0 ;like that ld hl,TimerTable ;this is the table at the end of this program add hl,bc ;put the offset on call LD_HL_MHL ;get the value from that address ld (DelayTimer),hl ;and that is the timer value call UpdateLevel ;update the level on the screen call UpdateScore ;update the score on the screen ld bc,$0D03 ;this is the address of the block to test call GetBlock ;check that block to see if somethngs there or a ;if something there jr nz,GameAllDone ;if block in that position, game all done call MakeNewSet ;puts in random numbers for next 3 call DrawCurrent ;and now we draw those three blocks jp keycheck ;and finally back to the main loop, yahoo!!! ;-------------- ;Sets vars for the next three blocks MakeNewSet: ld hl,$0D03 ;sets coords for the new three ld (YCoord),hl ;set them ld hl,Rand1 ;the address of the three random variables ld de,CurrTop ;the address of the three current blocks ld bc,3 ;move three bytes ldir ;put randoms into the new blcoks ret ;----------------- ;Tests for high scores, enter them, or return if not high GameAllDone: sub a ld (SavedGame),a ;since game all done, no game is saved ld hl,(Score) ;get score ex de,hl ;we just want hl in de ld a,(LevelDiff) ;branches off relative to LevelDiff cp 3 jr z,GameAllDone3 cp 4 jr z,GameAllDone4 cp 5 jr z,GameAllDone5 cp 6 jr z,GameAllDone6 cp 7 jr z,GameAllDone7 jr GameAllDone8 GameAllDone3: ;we're working on level 3 ld hl,(High3) ;get the high score or a ;clear carry flag sbc hl,de ;because this subtraction includes the carry flag jp nc,Start ;but it sets the carry flag if subtraction went over ;if high is higher, go all the way back to start ex de,hl ;now put _your_ score in hl, it was in de ld (High3),hl ;and put in new high score ld hl,High3Name ;this is used later jr HighScoreTime ;and go to enter the initials GameAllDone4: ld hl,(High4) ;see above or a sbc hl,de jp nc,Start ex de,hl ld (High4),hl ld hl,High4Name jr HighScoreTime GameAllDone5: ;see above ld hl,(High5) or a sbc hl,de jp nc,Start ex de,hl ld (High5),hl ld hl,High5Name jr HighScoreTime GameAllDone6: ;see above ld hl,(High6) or a sbc hl,de jp nc,Start ex de,hl ld (High6),hl ld hl,High6Name jr HighScoreTime GameAllDone7: ;see above ld hl,(High7) or a sbc hl,de jp nc,Start ex de,hl ld (High7),hl ld hl,High7Name jr HighScoreTime GameAllDone8: ;see above ld hl,(High8) or a sbc hl,de jp nc,Start ex de,hl ld (High8),hl ld hl,High8Name jr HighScoreTime ;----------------- ;enters the high scores HighScoreTime: push hl ;saves the table to enter initials call _clrLCD ;first we clear the screen, dum, de, dum ld hl,$0500 ;this is place for text ld (_curRow),hl ;load it in ld hl,HighScore ;High Score! call _puts ;put string ld hl,$0801 ;place for first initial ld (_curRow),hl ;load it ld hl,StringPlace ;this has your previous high score, from UpdateScore call _puts ;put that score ld b,3 ;3 initials as counter ld hl,$0903 ;place to put first initial ld (_curRow),hl ;right there pop hl ;now this is the place to store initials, from before InputLoop: push bc ;save the counter push hl ;save place to store initials ld a,$DF ;this is ti-ascii for the cursor call _putc ;put the cursor ld hl,_curCol ;this is the after putting the cursor dec (hl) ;put it back to where the cursor is KeyLoop: call GET_KEY ;gets the key ld c,a ;get table value from InputTable ld b,0 ; ld hl,InputTable add hl,bc ;by adding the keyvalue to InputTable ld a,(hl) ;and get the value or a ;if it is zero jr z,KeyLoop ;we still need a key pop hl ;get the initial address back ld (hl),a ;and load the first initial inc hl ;and move to the next initial call _putc ;put that initial pop bc ;counter... djnz InputLoop ;and get all three ld de,$FFFF ;or not, at which point we set up a delay LoopWait: dec de ;you've seen this before ld a,d or e jr nz,LoopWait jp Start ;and all done, so go back to intro screen ;---------------- ;puts the high score on the screen UpdateLevel: ld hl,$385D ;coords ld (_penCol),hl ;load in coord address ld a,(SpeedLevel) ;get the level add a,$31 ;this adds $30 to make it ascii, and one, to make it 1-8 ld hl,StringPlace ;place to store ascii digit ld (hl),a ;put it in ld b,1 ;one char call _vputsn ;and display one char pointed to by hl ret ;---------------- ;puts the score on screem UpdateScore: ld hl,$386B ;this is the cursor place ld (_penCol),hl ;and put it in ld hl,(Score) ;now we get score ld de,StringPlace+4 ;start of unpacking ld b,5 ;5 digits UpdateScore2: call UNPACK_HL ;divide hl by 10 and a contains remainder add a,'0' ;asciiize it ld (de),a ;put it in dec de ;next digit place to load djnz UpdateScore2 ;keep going ld hl,StringPlace ;now we put it back call _vputs ;and display the score ret ;--------------- ;Draw the current three blocks DrawCurrent: ld hl,(YCoord) ;get coords... push hl ; pop bc ;in bc ld a,(CurrBot) ;get bottom block push bc ;save coords call DrawBlock ;and draw it pop bc ;get coords back inc b ;inc y coord ld a,(CurrMid) push bc ;and so forth call DrawBlock pop bc inc b ld a,(CurrTop) call DrawBlock ret ;--------------- ;move the three down a notch MoveDown: ld hl,(YCoord) ;get coords ld a,h ;check x coord in a or a ;if xcoord zero, lowest possible jr z,IndicateFinish ;so indicate the finish, and leave dec h ;or else decrement x coord to check push hl ; pop bc ;put in bc call GetBlock ;this checks the block below, to see if it's done or a ;if so jr nz,IndicateFinish ;indicate the finish, and leave ld hl,(YCoord) ;if everything okay push hl ;save hl push hl ;put hl pop bc ;and get it in bc inc b ;go to the top block to erase that block inc b sub a ;blannk block call DrawBlock ;and draw it at the top pop hl ;coords saved dec h ;decrement it, xcoord ld (YCoord),hl ;and load them back call DrawCurrent ;Draw the Current three over the previous ones ret IndicateFinish: ld a,1 ;indiacte the finish with a boolean value ld (CurrFinished),a ;boolean to see if current set finished ret ;------------- ;This gets the value and address of the block specified by bc GetBlock: push bc ;save coords ld a,c ;use coord to find address rlca ;mult by 2 rlca ;mult by 2 rlca ;mult by 2 rlca ;mult by 2 - 16 in all add a,b ;now we add the ycoord ld c,a ld b,0 ;put it in bc ld hl,BlockMem ;get the BlockMem add hl,bc ;and here's the address ld a,(hl) ;block ID in a,address in hl pop bc ;saves bc ret ;---------------- ;Draws Block ID'd by a at coords b - (0-15) and c - (0-6) DrawBlock: push hl ;save hl push de ;save de push af ;save af which holds block rlc c ;mult y coord by 2 ld e,c ;use as offset ld d,0 ld hl,YTable ;add it to this table add hl,de ;like that call LD_HL_MHL ;now has hl row offset ld e,b ;now we put the x coord in de ld d,0 add hl,de ;now added the column offset push hl ;and now we pop de ;put it in de pop af ;this gets the block we saved on the stack rlca ;mult by 8 rlca rlca ;like that ld hl,Block0 ;now this contains all the blocks ld c,a ;put offset in bc ld b,0 add hl,bc ;now hl points to the bitmap block ld b,8 ;8 bytes to display ex de,hl ;de now contains vidmem spot, hl contains table Putloop: push bc ;save counter ld a,(de) ;get the bitmap byte from program ld (hl),a ;put in vidmem inc de ;next byte ld bc,$0010 ;but we have to inc the vidmem 16 bytes to nextline add hl,bc ;like that pop bc ;now the counter again djnz Putloop ;and all eight bytes display pop de ;saves de and hl pop hl ret ;--------------------- ;This routine displays the whole screen PutScreen: ; ld hl,BlockMem ;first block ld de,$0000 ;first coords ld b,7 ;7 rows PutScreen2: push bc ;save that counter ld b,16 ;16 rows PutScreen3: push bc ;save that counter push de ;put de pop bc ;in bc ld a,(hl) ;get that block! call DrawBlock ;saves de,hl, put block inc hl ;address inc d ;x coord pop bc ;get that counter djnz PutScreen3 ;loop till row finished ld d,0 ;xcoord zero inc e ;inc y coord pop bc ;and this counter djnz PutScreen2 ;and the outer loop ret ;screen all done LoadData: ld hl,$C089 ld (hl),$12 ;variable type inc hl ;now to the next spot ld (hl),$07 ;the length inc hl ;now we put in the name push hl ;save that ld hl,searchwords ;here's the name of program pop de ;pop it back into de ld bc,7 ;seven bytes for the ldir ldir ;loads it into the spot rst 10h ld a,b ex de,hl call $4633 set 6,a out (5),a inc a out (6),a ld bc,$4000 or a sbc hl,bc push hl ld hl,CurrTop ld de,$D748 or a sbc hl,de pop de add hl,de ld de,4 add hl,de ld de,CurrTop ex de,hl ld bc,175 ldir ld a,%00001101 out (5),a ld a,%01000001 out (6),a ret ;--------------------------------------------------------------------------- ;End of code, start of data ;These are the strings ;FORMAT - .db "KOLLUMS 1.0",0 ; ^ ^ ^ ;this is 'define byte' ^ and a zero on the end for _puts or _vputs ; ^ ; ^ ; Here is the string with quotation marks ; TitleStr: .db "KOLLUMS 2.0",0 Author: .db "By: Alan Bailey",0 Email: .db "",0 Difficulty: .db "Difficulty (l/r):",0 HighScore: .db "High Score!",0 HighStr: .db "High: ",0 ResumeStr: .db "Press F1 to Resume Game",0 searchwords: .db "kollums" ;This is the key table, takes the value from call GET_KEY ;and converts it to this ascii character InputTable: .db 0,0,0,0,0,0,0,0,0,0 .db 'X','T','O','J','E',0,0 .db ' ','W','S','N','I','D',0,0 .db 'Z','V','R','M','H','C',0,0 .db 'Y','U','Q','L','G','B',0,0,0,0 .db 'P','K','F','A',0,0,0,0,0,0,0,0,0,0 ;This is the value of the timers used to speed up the game TimerTable: .dw $0660,$05A0,$04E0,$0420,$0360,$02A0,$01E0,$0120 ;7 y coord offsets for lookup YTable: .dw $FC00,$FC80,$FD00,$FD80,$FE00,$FE80,$FF00 CurrTop: .db 0 CurrMid: .db 0 CurrBot: .db 0 CurrFinished: .db 0 Randomed: .db 0 YCoord: .db 0 XCoord: .db 0 Rand1: .db 0 Rand2: .db 0 Rand3: .db 0 StartBlock: .dw $0000 TotalBlockCount: .db 0 BlockDiff: .db 0 DelayTimer: .dw $0660 Score: .dw $0000 SpeedLevel: .db 0 StringPlace: .db 0,0,0,0,0,0 BlockMem: .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;this variable is stored in the program because we want to save it LevelDiff: .db $06 ;this one we want to keep ;along with these high score variables High3: .db $01,$00 High3Name: .db 'A','B','C',$00 ;plus zero terminator High4: .db $01,$00 High4Name: .db 'D','E','F',$00 High5: .db $01,$00 High5Name: .db 'G','H','I',$00 High6: .db $01,$00 High6Name: .db 'J','K','L',$00 High7: .db $01,$00 High7Name: .db 'M','N','O',$00 High8: .db $01,$00 High8Name: .db 'P','Q','R',$00 SavedGame: .db 0 ;set if a game is saved ;this are simple bitmaps of blocks Block0: .db %00000000 .db %00000000 .db %00000000 .db %00000000 .db %00000000 .db %00000000 .db %00000000 .db %00000000 Block1: .db %00000000 .db %01111111 .db %01000001 .db %01000001 .db %01000001 .db %01000001 .db %01000001 .db %01111111 Block2: .db %00000000 .db %01111111 .db %01111111 .db %01111111 .db %01111111 .db %01111111 .db %01111111 .db %01111111 Block3: .db %00000000 .db %00001000 .db %00011100 .db %00111110 .db %01111111 .db %00111110 .db %00011100 .db %00001000 Block4: .db %00000000 .db %01100011 .db %01100011 .db %00010100 .db %00001000 .db %00010100 .db %01100011 .db %01100011 Block5: .db %00000000 .db %01010101 .db %00101010 .db %01010101 .db %00101010 .db %01010101 .db %00101010 .db %01010101 Block6: .db %00000000 .db %01111111 .db %01001001 .db %01001001 .db %01111111 .db %01001001 .db %01001001 .db %01111111 Block7: .db %00000000 .db %00001000 .db %00010100 .db %00100010 .db %01000001 .db %00100010 .db %00010100 .db %00001000 Block8: .db %00000000 .db %01111111 .db %00111110 .db %00011100 .db %00001000 .db %00011100 .db %00111110 .db %01111111 .end ;tells TASM it's all over