| CODE |
/* Filename: biline.c Project: EE 476 Final Project: BiLines Class: EE 476 Cornell University Created by: Michael Jordan and Crystal Soja Last Updated: April 30, 2001 */ #include <90s8515.h> #include <c:\cvavr\inc\delay.h> //#include <stdio.h> //for debugging using printf, etc #include <stdlib.h> //*Timer 1 defines only */ #define prescale1 3 // 011 CK/64 p 30 #define clear_on_match 8 /****************************/ //Timer 0 defines #define reload0 200 //so overflow every 30 msec (138) #define prescale0 4 //1024 /****************************/ /***************BEGIN LCD DEFINES ***********************/ //LCD control lines using PORTC A0 WRbar RDbar Rbar #define lcdRESET 0x00 // 0 0 0 0 #define lcdNOP 0x47 // 1 1 1 1 #define cmdSet 0x47 // 1 1 1 1 #define cmdWR 0x43 // 1 0 1 1 #define dataSet 0x07 // 0 1 1 1 #define dataWR 0x03 // 0 0 1 1 #define StatRD 0x05 // 0 1 0 1 #define DataRD 0x45 // 1 1 0 1 //LCD COMMANDS using PORTD #define SystemSet 0x40 //initialize device & display #define SleepIn 0x53 //enter standby mode #define DispON 0x59 //enable display/display flashing #define DispOFF 0x58 //disable display/display flashing #define Scroll 0x44 //set display start addres & display regions #define CSRform 0x5D //set cursor type #define CGRAMaddr 0x5C //set start address of char. generator RAM #define CSRup 0x4E //set cursor direction movement to up #define CSRdown 0x4F //set cursor direction movement to down #define CSRleft 0x4D //set cursor direction movement to left #define CSRright 0x4C //set cursor direction movement to right #define HorScroll 0x5A //set horizontal scroll position #define Ovlay 0x5B //set display overlay format #define CSRW 0x46 //set cursor address #define CSRR 0x47 //read cursor address #define mWR 0x42 //write to display memory #define mRD 0x43 //read from display memory //Other constants #define BytesperLine 40 //number of characters on a line #define MaxCharLine 25 //number of character lines #define statAddr 26 //address where level,score,etc. text goes, so aligned #define beginGraphicsMem 0x3E8 //not used #define ScoreAddr (BytesperLine*0x15+statAddr+8) //where score written #define HiScoreAddr (BytesperLine*0x17+statAddr+8) //where hiscore written #define LineAddr (BytesperLine*0x13+statAddr+8) //where lines cleared written #define PieceAddr (BytesperLine*0x14+statAddr+8) //where piece number written #define LevelAddr (BytesperLine*0x12+statAddr+8) //where level written #define NextPieceAddr 0x79C //where next piece drawn /******************* END CRYSTAL'S DEFINES ********************/ void initialize(void); //all the usual mcu stuff void updatedisplay(void); //update the LCD for current piece falling void nextpiece(void); //generate next piece "randomly" void drawNoBox(int addr); //draw a null box to the display at address void writeInt(int addr, int integer); //write as integer to the screen (e.g. score) void moveright(void); //check on button press //and move current piece right if possible void moveleft(void); //check on button press //and move current piece left if possible void rotatepiece(void); //check on button press //and rotate current piece if possible void drawnextpiece(void); //draw next piece to display void updateprevious(void); void drawline(void); //draws verticle line on screen for game board void drawBoardEdge(void); //draws line on rhs of game board void gameover(void); //handles gameover conditions and display to LCD void sendmusic(void); //sends music bits to other board void startUpScreen(void); //special screen on startup void clearLeftScreen(void); //clears text on game board (lhs of screen) void beginGame(void); //begin a new BiLine game /* VARIABLES ****************************************/ //other variables unsigned short temp, i, j, score, lines, pieces,hiscore,level; //temporary variables,status variables unsigned char state, butState, next, temp2, gameoverflag, winflag,loseflag,twoplayer; //state variables unsigned char CharInt[16]; //used to print out integers to screen //used to draw Left Hand side of block char blockL[]={0xFF,0x80,0xBF,0xBF,0xBF,0xBF,0xBF,0xBF,0xBF,0xBF,0xBF,0x80,0xFF}; //used to draw Right hand side of block char blockR[]={0xFC,0x04,0xF4,0xF4,0xF4,0xF4,0xF4,0xF4,0xF4,0xF4,0xF4,0x04,0xFC}; //press start for new game... message char newGameMessage[28]={'P','r','e','s','s','','"','S','t','a', 'r','t','"','f','o','r','','a',' ','n','e','w', '','g','a','m','e','.'}; //start-up screen message char startUpMessage[65]={'B','i','L','i','n','e','s','','c','r','e','a','t','e','d', '','b','y','','M','i','c','h','a','e','l',' ','J','o','r', 'd','a','n',' ','a','n','d',' ','C','r','y','s','t','a','l', '','S','o','j','a',' ','C','o','p','y','r','i','g','h','t', ' ','2','0','0','1'}; int OCRvals[] = {31250,25000,18750,15625,12500,11250,9375,7812,6250,5000}; //different TIM1 COMPA OCR1A values for each level unsigned char OCRvalue; //index into OCRvalus[OCRvalue] unsigned char OCRcount; //counts number of TIM1 COMPA interupts for a "fast down" unsigned int musicwaitcount; //timing variable for synchronization with music board unsigned int piece[8][4] = { {0b0010011001100100,0b0000111001110000,0b0010011001100100,0b0000111001110000}, {0b0000000001000000,0b0000000001000000,0b0000000001000000,0b0000000001000000}, {0b0000000001000100,0b0000000011000000,0b0000000001000100,0b0000000011000000}, {0b0000010001110100,0b0000011100100010,0b0000000101110001,0b0000001000100111}, {0b0000010001000111,0b0000011101000100,0b0000011100010001,0b0000000100010111}, {0b0000010001000110,0b0000111010000000,0b0000011000100010,0b0000001011100000}, {0b0000001000100110,0b0000100011100000,0b0000011001000100,0b0000111000100000}, {0b0100011001100010,0b0000011111100000,0b0100011001100010,0b0000011111100000} }; /* All of the different pieces and rotational combinations of piece[p][t] = piece[piece][type]. The decoding of these bits appear as: Piece definitions from above top to bottom, left to right: */ /* 0 0 1 0 0 0 0 0 0 1 1 0 or 1 1 1 0 0 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 piece[0][0] piece[0][1] */ /* 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 piece[1][0] */ /* 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0 1 0 0 0 0 0 0 piece[2][0] piece[2][1] */ /* 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 or 0 1 1 1 or 0 0 0 1 or 0 0 1 0 0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 1 0 1 1 1 piece[3][0] piece[3][1] piece[3][2] piece[3][3] */ /* 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 or 0 1 1 1 or 0 1 1 1 or 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1 1 0 1 0 0 0 0 0 1 0 1 1 1 piece[4][0] piece[4][1] piece[4][2] piece[4][3] */ /* 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 or 1 1 1 0 or 0 1 1 0 or 0 0 1 0 0 1 0 0 1 0 0 0 0 0 1 0 1 1 1 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 piece[5][0] piece[5][1] piece[5][2] piece[5][3] */ /* 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 or 1 0 0 0 or 0 1 1 0 or 1 1 1 0 0 0 1 0 1 1 1 0 0 1 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 piece[6][0] piece[6][1] piece[6][2] piece[6][3] */ /* 0 1 0 0 0 0 0 0 0 1 1 0 or 0 1 1 1 0 1 1 0 1 1 1 0 0 0 1 0 0 0 0 0 piece[7][0] piece[7][1] */ unsigned char p; //the piece (index of piece[p][]) unsigned char t; //the piece type (index of piece[t]) unsigned char tt; //temp t variable for checking button conditions unsigned char tprev; //previous t variable for rotate piece /* ***************************** */ /* Variables for the Board only */ unsigned int board[25]; //physical playing board unsigned int tempboard1; //temp 4x4 area of board repr 4x4 board area under piece //(cmpA) unsigned int templine0; unsigned int templine1; //5 temp lines representing the board OR piece (cmpA) unsigned int templine2; unsigned int templine3; unsigned int templine4; unsigned char current; //current (vertical) line number of piece on board unsigned char index; //current (horizontal) line number of piece on board unsigned char tindex; //temp index for checking button conditions unsigned char indexprev; //previous index for rotate piece /* b b b b b b b b b b /^\ b b b b b b b b b b | b b x x x x b b b b | b b x x x x b b b b 18 lines b b x x x x b b b b | current -> x x x x b b b b | index--| b b b b b b b | b b b b b b b b b b \_/ <-- 10 lines -- > */ /*****************************************************************/ unsigned char count; //number (location) of lines that will be cleared (cmpA) unsigned char k; //index variables for for loops: note these are GLOBAL unsigned char kk; unsigned char kkk; unsigned char random; //random piece value unsigned char tbit; //either '1' or '0' 1 if draw box at address 0 if drawnobox unsigned int address; //address for LCD display unsigned char line; //line that void drawline() clears unsigned char music; //which music to play unsigned char pauseflag; //paused when pauseflag =1 void LCDbaseWR(void); //draws the base screen for LCD void drawBox(int addr); //draws building block for pieces /**********************************************************************/ //sequencing to address the lcd controller appropriately to write command void WRcmd(char comCode) { PORTA = comCode; //put command on portA PORTC = cmdSet; //get port ready for command PORTC = cmdWR; //write command PORTC = cmdSet; //settle portc } /**********************************************************************/ /**********************************************************************/ //sequencing to address the lcd controller appropriately to write data void WRdata(char comCode) { PORTA = comCode; //put command on portA PORTC = dataSet; //get port ready for command PORTC = dataWR; //write data PORTC = dataSet; //settle portc } /**********************************************************************/ /**********************************************************************/ //clear the entire lcd - both character and graphic displays void clearLCD(void) { //make cursor move right WRcmd(CSRright); //set cursor address to 0x0000 WRcmd(CSRW); WRdata(0x00); WRdata(0x00); //prepare to write WRcmd(mWR); //write nothing to all character space for(temp=0; temp<1000; temp++) WRdata(0x20); //set cursor address to 0x03E8 WRcmd(CSRW); WRdata(0xE8); WRdata(0x03); //prepare to write WRcmd(mWR); //write to all of graphics memory for(temp=0; temp<8000; temp++) WRdata(0x00); } /**********************************************************************/ //initilization for the LCD void initLCD(void) { //from documentation, all commands needed to initialize the lcd properly delay_ms(2); PORTC = lcdRESET; delay_ms(2); PORTC = lcdNOP; WRcmd(SystemSet); WRdata(0x30); WRdata(0x87); WRdata(0x07); WRdata(0x27); WRdata(0x2F); WRdata(0xC7); WRdata(0x28); WRdata(0x00); WRcmd(Ovlay); WRdata(0x00); WRcmd(Scroll); WRdata(0x00); WRdata(0x00); WRdata(0xC8); WRdata(0xE8); WRdata(0x03); WRdata(0xC8); WRcmd(CSRform); WRdata(0x04); WRdata(0x86); WRcmd(CSRright); WRcmd(HorScroll); WRdata(0x00); WRcmd(DispON); WRdata(0x14); //no cursor clearLCD(); //clear lcd WRcmd(CSRW); //move to 0x001D WRdata(0x1D); WRdata(0x00); WRcmd(mWR); //write game title on RHS WRdata('B'); WRdata('i'); WRdata('L'); WRdata('i'); WRdata('n'); WRdata('e'); WRdata('s'); LCDbaseWR(); //set up base screen for BiLines } /**********************************************************************/ void LCDbaseWR(void) { //here write like where the line down the middle goes, text for score //basic 'look' of the game even when pieces arent there. WRcmd(CSRW); WRdata(BytesperLine*0x12+statAddr); WRdata(BytesperLine*0x12+statAddr>>8); WRcmd(mWR); WRdata('L'); WRdata('E'); WRdata('V'); WRdata('E'); WRdata('L'); WRdata(' '); WRcmd(CSRW); WRdata(BytesperLine*0x15+statAddr); WRdata(BytesperLine*0x15+statAddr>>8); WRcmd(mWR); WRdata('S'); WRdata('C'); WRdata('O'); WRdata('R'); WRdata('E'); WRdata(' '); WRcmd(CSRW); WRdata(BytesperLine*0x13+statAddr); WRdata(BytesperLine*0x13+statAddr>>8); WRcmd(mWR); WRdata('L'); WRdata('I'); WRdata('N'); WRdata('E'); WRdata('S'); WRdata(' '); WRcmd(CSRW); WRdata(BytesperLine*0x14+statAddr); WRdata(BytesperLine*0x14+statAddr>>8); WRcmd(mWR); WRdata('P'); WRdata('I'); WRdata('E'); WRdata('C'); WRdata('E'); WRdata(' '); WRcmd(CSRW); WRdata(BytesperLine*0x17+statAddr); WRdata(BytesperLine*0x17+statAddr>>8); WRcmd(mWR); WRdata('H'); WRdata('I'); WRdata('S'); WRdata('C'); WRdata('O'); WRdata('R'); WRdata('E'); WRdata(' '); WRcmd(CSRW); WRdata(0x1C+(10*BytesperLine)); WRdata(0x1C+(10*BytesperLine)>>8); WRcmd(mWR); WRdata('N'); WRdata('e'); WRdata('x'); WRdata('t'); WRdata(' '); WRdata('P'); WRdata('i'); WRdata('e'); WRdata('c'); WRdata('e'); //write all the initial hiscore, lines, score, pieces,level writeInt(HiScoreAddr,hiscore); writeInt(LineAddr,lines); writeInt(ScoreAddr,score); writeInt(PieceAddr,pieces); writeInt(LevelAddr,level); drawBoardEdge(); //draws line on rhs of board startUpScreen(); //displays initial text on LHS when game begins //http://www.seiko-usa-ecd.com/lcd/pdf/graphic/Sed1335f.pdf //application notes section } /**********************************************************************/ //this box type has black outline, white outline then filled in. //draws box wrt the address passed in //used as basic building block for for all BiLine pieces void drawBox(int addr) { WRcmd(CSRW); WRdata(addr); WRdata(addr>>8); //lh block WRcmd(mWR); //if makes sure stay inside of graphics space and blocks are not drawn outside if(addr>0x04B0){ for(i=0;i<8;i++){WRdata(blockL[i]);} WRcmd(CSRW); WRdata(addr+1); WRdata(addr+1>>8); WRcmd(mWR); for(i=0;i<8;i++){WRdata(blockR[i]);} } WRcmd(CSRW); WRdata(addr+0xF0); WRdata(addr+0xF0>>8); WRcmd(mWR); for(i=8;i<13;i++) { WRdata(blockL[i]); } WRcmd(CSRW); WRdata(addr+0xF1); WRdata(addr+0xF1>>8); WRcmd(mWR); for(i=8;i<13;i++) { WRdata(blockR[i]); } } //undraws block given an address //like with drawBox does not let the program draw outside graphics space void drawNoBox(int addr) { WRcmd(CSRW); WRdata(addr); WRdata(addr>>8); WRcmd(mWR); if(addr>0x04B0){ for(i=0;i<8;i++){ WRdata(''); } //rh block WRcmd(CSRW); WRdata(addr+1); WRdata(addr+1>>8); WRcmd(mWR); for(i=0;i<8;i++){ WRdata(''); } } WRcmd(CSRW); WRdata(addr+0xF0); WRdata(addr+0xF0>>8); WRcmd(mWR); for(i=8;i<13;i++) {WRdata(''); } WRcmd(CSRW); WRdata(addr+0xF1); WRdata(addr+0xF1>>8); WRcmd(mWR); for(i=8;i<13;i++) {WRdata(''); } } //draws a verticle line on the RHS of the board void drawBoardEdge(void) { for(j=0;j<34;j++) { WRcmd(CSRW); WRdata(0x4B0+(0xF0*j)+20); WRdata((0x4B0+(0xF0*j)+20)>>8); WRcmd(mWR); for(i=0;i<8;i++) { WRdata(0xC0); } } } //draws the start up message appropriately //BiLines //Crystal Soja //and //Michael Jordan // //Copyright 2001 void startUpScreen(void) { WRcmd(CSRright); WRcmd(CSRW); WRdata(7+5*40); WRdata(7+5*40>>8); WRcmd(mWR); for(i=0;i<8;i++){ WRdata(startUpMessage[i]); } WRcmd(CSRW); WRdata(6+7*40); WRdata(6+7*40>>8); WRcmd(mWR); for(i=8;i<19;i++){ WRdata(startUpMessage[i]); } WRcmd(CSRW); WRdata(4+8*40); WRdata(4+8*40>>8); WRcmd(mWR); for(i=19;i<33;i++){ WRdata(startUpMessage[i]); } WRcmd(CSRW); WRdata(8+9*40); WRdata(8+9*40>>8); WRcmd(mWR); for(i=33;i<37;i++){ WRdata(startUpMessage[i]); } WRcmd(CSRW); WRdata(4+10*40); WRdata(4+10*40>>8); WRcmd(mWR); for(i=37;i<51;i++){ WRdata(startUpMessage[i]); } WRcmd(CSRW); WRdata(4+14*40); WRdata(4+14*40>>8); WRcmd(mWR); for(i=51;i<65;i++){ WRdata(startUpMessage[i]); } WRcmd(CSRdown); } //goes through and clears entire character space in the game side of the screen (LHS) void clearLeftScreen(void) { WRcmd(CSRright); //cursor to the right for(j = 0; j<20; j++){ WRcmd(CSRW); WRdata(0x0000+40*j); WRdata((0x0000+40*j)>>8); WRcmd(mWR); for(i=0;i<25;i++){ WRdata(''); } } WRcmd(CSRdown); //cursor down } //writes integers to the LCD screen given an address and an integer void writeInt(int addr, int integer){ WRcmd(CSRright); //cursor to the right for(i= 0; i<16; i++){ CharInt[i]=''; } //clear CharInt array itoa(integer, CharInt); //convert the integer into the character array //cycle through character array and print to screen for(i= 0; i<16; i++){ WRcmd(CSRW); WRdata(addr+i); WRdata((addr+i)>>8); WRcmd(mWR); WRdata(CharInt[i]); } WRcmd(CSRdown); //cursor down } interrupt [TIM0_OVF] void timer0_overflow(void) { TCNT0 = reload0; //reload timer0 temp2++; //the random seed for the pseudo-random piece choice //sets up the timing appropriately for communicating with the sound board if (musicwaitcount == 10) { if(music == 0b00000100) musicwaitcount = 0; //so continue to play Fur Elise in the intro screen else musicwaitcount++; //sets the communication lines to the SoundBoard all to zero PORTD.4 = 1; PORTD.3 = 1; PORTD.2 = 1; music = 0b00000111; //set music to match value on ports } else if(musicwaitcount > 300) { if (gameoverflag==0) // if in the middle of the game, play cannon in D { music = 0b00000100; sendmusic(); } musicwaitcount = 0; //reset musicwait count } else if ( (PORTD.2 == 0) || (PORTD.3 == 0) || (PORTD.4 == 0)||(musicwaitcount>0)) { musicwaitcount++; //increment musicwaitcount if any PORT is set to 0, or musicwaitcount not 0 } //state machine for pushbuttons switch(state) { case 1: //check for button press if(PINB == 0xFF && PINC.7 == 1) { break; } else { state = 2; //if pressed move to state2 butState= ((PINB<<1)>>1)|(PINC.7<<7); //printf("butState is %d",butState); } break; case 2: //actions occur here //if(PINB == butState) { if(((PINB<<1)>>1)|(PINC.7<<7) == butState){ state = 3; if(PINB.0 == 0x00) { //pause TCCR1B = 0; pauseflag = 1; music = 0b00000110; //start/pause music sendmusic(); //printf("pause pressed"); } if(PINB.1 == 0x00) { //start if (PIND.0 == 1) { music = 0b00000110; //start/pause sendmusic(); if (gameoverflag == 1) { //if game over, and start pressed, run intialGame code p = (temp2<<5)>>5; beginGame(); } pauseflag = 0; //unpause gameoverflag = 0; //set gameoverflag to true (have started a game, or are in game) TCCR1B = prescale1 + clear_on_match; //turn timer1 on //PORTD.1 = 1; //printf("start pressed"); } PORTD.1 = 1; //two-player start, wait for second player to start } if(PINB.2 == 0x00 && pauseflag !=1) { //rotate CW //printf("rotate CW, t = %d",t); //************************************* //may have to fix this if change pieces rotatepiece(); //rotate piece } if(PINB.3 == 0x00) { //drop TCNT1 = 490; OCR1A = 500;//try also 1000 //printf("drop pressed"); } if(PINB.4 == 0x00 && pauseflag != 1) { //move right moveright(); } if(PINC.7 == 0x00) { //fast down //printf("fast down \n\r"); TCNT1 = 490; OCR1A = 500; OCRcount = 1; } if(PINB.6 == 0x00 && pauseflag !=1) { //move left moveleft(); } } else state = 1; break; case 3: //check for button release if(PINB == butState) state=3; else state = 1; break; case 4: //make sure really released if(PINB == butState) state = 3; else { state = 1; butState = 0xFF; } break; default: break; } } //********************************************************** //timer 1 compare-match A ISR //Dropping a Piece interrupt [TIM1_COMPA] void cmpA_overflow(void) { if(PIND.5==1) //(If 2nd player playing, and other player lost game.) { if (gameoverflag == 0) //If the first time in this loop { gameoverflag = 1; //Set already in this loop loseflag = 0; //Didn't lost winflag = 1; //Won game gameover(); //Update LCD for gameover conditions music = 0b00000001; //Select gameover music sendmusic(); //Send gameover music control } return; } /* Is it possible to drop 1? tempboard1 - 16 bits repr the 4x4 area from current-1 to current+2 x x x x current + 2 x x x x x x x x current x x x x current - 1 index --| */ tempboard1 = 0; //clear this out (was having problems clearing this var) tempboard1 = ((board[current-1])<<index)>>12; //4 bits index to index + 3 of board[current-1] templine2 = tempboard1; //botton 4 bits of tempboard1 tempboard1 = tempboard1 | (((board[current])<<index)>>12)<<4; //add in 4 bits starting at index for current templine3 = tempboard1; //botton 8 bits of tempboard1 tempboard1 = tempboard1 | (((board[current+1])<<index)>>12)<<8; //add in 4 bits for current +1 tempboard1 = tempboard1 | (((board[current+2])<<index)>>12)<<12; //add in 4 bits for current +2 templine3 = (((board[current])<<index)>>12)<<4; //bottom 8 bits of tempboard1 //General Case: Check if piece can be dropped by 1 //General case occurs when current piece is above 3 (i.e. //the bottom of the visible part of the game board. if (((piece[p][t] & tempboard1) == 0) && current >3 ) { //If the user has pressed "Fast Drop" reset original OCR1A //after 1 interrrupt if (OCRcount > 1) { OCR1A = OCRvals[OCRvalue]; OCRcount = 0; } else if (OCRcount > 0) { OCRcount++; } current--; //Decrement current row of current piece updatedisplay(); //reflect this change in the LCD } /* Special Case 1: Check if current piece can be extended to one level below the current level of the playing board i.e. for the piece: 0 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 This case allows for the piece to drop to the bottom of the visible area by allowing the zeros to go below the screen. piece[p][t]<<12)>>12) == 0 => bottom of piece is 0 0 0 0 templine2 == 0 => bottom of board is 0 0 0 0 */ else if (( ((piece[p][t]<<12)>>12) == 0) && (templine2 == 0) && ((piece[p][t] & tempboard1)==0)&& (current >2)) { //If the user has pressed "Fast Drop" reset original OCR1A //after 1 interrrupt if (OCRcount > 1) { OCR1A = OCRvals[OCRvalue]; OCRcount = 0; } else if (OCRcount > 0) { OCRcount++; } current--; //Decrement current row of current piece updatedisplay(); //reflect this change in the LCD } /* Special Case 2: Check if current piece can be extended to two levels below the current level of the playing board Note that this case does not occur with the current pieces, but we leave it in so that we change the pieces with greater ease. */ else if (( ((piece[p][t]<<8)>>12) == 0) && templine3 == 0 && ((piece[p][t] & tempboard1)==0) && current >1) { //If the user has pressed "Fast Drop" reset original OCR1A //after 1 interrrupt if (OCRcount > 1) { OCR1A = OCRvals[OCRvalue]; OCRcount = 0; } else if (OCRcount > 0) { OCRcount++; } current--; //Decrement current row of current piece updatedisplay(); //reflect this change in the LCD } else //block stays at current position { //Check to see if user has ended the game by having the current //piece stuck at the top of the screen if (current >= 19) { if(gameoverflag==0) //first iteration in this loop { PORTD.6 = 1; //signal to other board that this user has lost the game loseflag = 1; //set the loseflag for gameover() gameover(); //update LCD with game info music = 0b00000001; //set the music choice to gameover music sendmusic(); //send music to other board gameoverflag = 1; //indicate this is first time in loop if(score > hiscore) {hiscore = score; writeInt(HiScoreAddr,hiscore); } //update hiscore if hiscore is surpasssed } return; } //clear and put in upper 4 /shift to right position templine0 = board[current-1] | 0b1000000000011111; //bits of the board in the viewable board space //4 lines representing the 4 viewable lines from current to current + 3 //we use these templines to check if any of them can be cleared //note that we OR with ones outside the viewable area for this check =) templine1 = ( (piece[p][t]<<12) >>index) |board[current] | 0b1000000000011111; templine2 = (((piece[p][t]>> 4)<<12)>>index) | board[current+1]| 0b1000000000011111; templine3 = (((piece[p][t]>> 8)<<12)>>index) | board[current+2]| 0b1000000000011111; templine4 = (((piece[p][t]>>12)<<12)>>index) | board[current+3]| 0b1000000000011111; //clear 1 line? //if (board[current] | temppiece1 == 1} //since the piece has stopped, add make the current piece part of the board //and set the bits outside the viewable area back to zero //why do we do this? if the outside bits are not zeros, then the checks for //button rotate, left, and right, become invalid board[current] = templine1 & 0b0111111111100000; board[current+1] = templine2 & 0b0111111111100000; board[current+2] = templine3 & 0b0111111111100000; board[current+3] = templine4 & 0b0111111111100000; count = 10; //mark count //this series of if statements determine the number of lines above //current that the two lines to be cleared (if any) occur if ( (templine0 ==-1) && (templine1 == -1) ) { count = 0; } else if ( (templine1 ==-1) && (templine2 == -1) ) { count=1; } else if ( (templine2 ==-1) && (templine3 == -1) ) { count=2; } else if ( (templine3 ==-1) && (templine4 == -1) ) { count=3; } if (count!=10) //line cleared { music=0b00000010; //line cleared music sendmusic(); //cool flashing transition templine1 = board[current+count-1]; templine2 = board[current+count]; for(k=0;k<15;k++) { board[current+count-1] = 0; board[current+count] = 0; line = current+count-1; drawline(); line = current+count; drawline(); board[current+count-1] = templine1; board[current+count] = templine2; line = current+count-1; drawline(); line = current+count; drawline(); } //end cool flashing transition //move lines above (current+count+1) to current kk=current+count-1; for(k=(count+current+1);k<21;k++,kk++) { board[kk] = 0; //clear line (was having trouble clearing before) board[kk] = board[k]; //move line down } for (k=19;k<24;k++) { board[k] = 0; //clear lines above visible board to zero so that //they don't drop down later. } board[0] = 0; //clear lines below the visible board board[1] = 0; board[2] = 0; for(k=0;k<19;k++) //update all the lines on the screen. { line = k; drawline(); } score+=45; //add 45pts b/c cleared the two lines! lines+=2; //update line count writeInt(LineAddr,lines);//send this info to the display }//end if; //next piece generation. t=0; //piece will be at rotation 0 current = 19; //next piece will start at top of screen index = 5; //piece starts at middle of screen p=next; //piece is next piece nextpiece(); //display next piece writeInt(LineAddr,lines); //write lines to display if (((lines+1)%20) == 0) //every 20 lines increment level { level++; writeInt(LevelAddr,level); if (OCRvalue < 9) //increment speed of dropping blocks if not //at top level { OCRvalue++; } } OCR1A = OCRvals[OCRvalue]; score+=5; //increment score by 5 for new piece pieces++; //increment # of pieces user got writeInt(ScoreAddr,score); writeInt(PieceAddr,pieces); }//end else }//end end //Draw board[line] to the display. line is set before entering the void(). void drawline(void) { for (kkk=1;kkk<11;kkk++) { tbit = ((board[line]<<kkk)>>15); //tbit = the particular bit //as a check to make sure that other parts dont try to draw a line //outside of the visible region (an invalid LCD address) make this check //first if ((19-(line)) <= 19 && (kkk-1) < 10) //was 11 { address = 0x3C0+(19-line)*2*0xf0+(kkk-1)*2; //set address of each block in line if (tbit == 1) { drawBox(address); } else { drawNoBox(address); } } } } //Called on user pressing rotate button //Check to see if piece can be rotate, if can then rotate it void rotatepiece(void) { if (t<3) //Each piece has 4 rotations thus increment the temp { tt=t+1; } else { tt=0; //or set the temp to zero if was at 3 } //Sine rotating clockwise we need to check if the right two columns of the piece //at the next rotation will cause the piece to be outside of the viewable area templine1 = (((piece[p][tt]<<12)>>15) | ((piece[p][tt]<< 8)>>15) | ((piece[p][tt]<< 4)>>15) | ((piece[p][tt] )>>15) ); //column of piece at index + 3 templine2 = (((piece[p][tt]<<15)>>15) | ((piece[p][tt]<<11)>>15) | ((piece[p][tt]<< 7)>>15) | ((piece[p][tt]<< 3)>>15) ); //column of piece at index + 2 tprev = t; if ((index >= 1 && index <=7) || ((index == 0) && (templine1 == 0)) || ((index == 8) && (templine2 == 0))) //Make the rotation t, the next rotation tt only if piece contained within //the visible area, or the the far right two column are all 0's. Thus we //cant rotate if on an edge. { if(t<3) { tt=t+1; } else { tt = 0; } //We now need to check if if that rotation of the piece will cause a collision //with blocks that are already on the board on a drop of 1 level of current (the //interrupt. //Same as above, tempboard1 represents the 4x4 grid of board overlaying the proposed //future value of the piece. tempboard1 = 0; tempboard1 = ((board[current])<<index)>>12; tempboard1 = tempboard1 | (((board[current+1])<<index)>>12)<<4; tempboard1 = tempboard1 | (((board[current+2])<<index)>>12)<<8; tempboard1 = tempboard1 | (((board[current+3])<<index)>>12)<<12; if (((piece[p][tt] & tempboard1) == 0)) //if all 0's => no "collision with the board { //wont flip if at bottom or too close to other pieces //Will there be a collision if the piece has dropped by two positions? //This is necessary to institute because of the time it takes to rotate //the piece tempboard1 = 0; tempboard1 = ((board[current-2])<<index)>>12; tempboard1 = tempboard1 | (((board[current-1])<<index)>>12)<<4; tempboard1 = tempboard1 | (((board[current])<<index)>>12)<<8; tempboard1 = tempboard1 | (((board[current+1])<<index)>>12)<<12; //If above conditions are met then we rotate the piece. if (((piece[p][tt] & tempboard1) == 0)) { t=tt; } } } } //Called on user pressing move right button //Check to see if piece can be moved right, if so move it right. void moveright(void) { indexprev = index; //store prev index value if(index < 9) // => we can move right { if ( (index == 7) &&(((piece[p][t]<<15)>>15) | ((piece[p][t]<<11)>>15) | ((piece[p][t]<< 7)>>15) | ((piece[p][t]<< 3)>>15)) == 0 ) //special case where we need the piece to have 0's along the right most //column, i.e. at index + 3 { tindex=8; } else if ( (index == 8) &&(((piece[p][t]<<14)>>15) | ((piece[p][t]<<10)>>15) | ((piece[p][t]<< 6)>>15) | ((piece[p][t]<< 2)>>15)) == 0 ) //special case where we need the piece to have 0's along the left most //column, i.e. index + 2. note that we are already assured that that //we have 0's along the right most column because we had to have previously //entered the previous case (index=7) above { tindex=9; } else if (index <7) //the general case, can automatically move left (assuming no collision) { tindex = index+1; } if (current < 18) //as long as current line is less than 18, we need to check if the movement //of the piece will cause a collision with any blocks current only the board { tempboard1 = 0; tempboard1 = ((board[current])<<tindex)>>12; tempboard1 = tempboard1 | (((board[current+1])<<tindex)>>12)<<4; tempboard1 = tempboard1 | (((board[current+2])<<tindex)>>12)<<8; tempboard1 = tempboard1 | (((board[current+3])<<tindex)>>12)<<12; if (((piece[p][t] & tempboard1) == 0)) //thus if no collision we can change index to the temp value { index=tindex; } updateprevious(); //update screen } } } //Called on user pressing move left button //Check to see if piece can be moved left, if so move it left. void moveleft(void) { indexprev = index; //create a sample index to check if possible to move left if (index>0) //these index values will allow movement left { if ( (index == 1) &&(((piece[p][t]<<12)>>15) | ((piece[p][t]<< 8)>>15) | ((piece[p][t]<< 4)>>15) | ((piece[p][t]) >>15)) == 0 ) //special condition of index=1, we need the left most column, i.e. column //at index to be all 0's in order for a shift left { tindex=0; } else if (index >1) //general case allows movement left (assuming no collision) { tindex = index-1; } if (current <18) //as long as not gameover we now need to check if moving this piece will //cause any interference with blocks already on the board { tempboard1 = 0; tempboard1 = ((board[current])<<tindex)>>12; tempboard1 = tempboard1 | (((board[current+1])<<tindex)>>12)<<4; tempboard1 = tempboard1 | (((board[current+2])<<tindex)>>12)<<8; tempboard1 = tempboard1 | (((board[current+3])<<tindex)>>12)<<12; if (((piece[p][t] & tempboard1) == 0)) //assuming no collisions move the piece left { index=tindex; } updateprevious(); //update screen } } } //generate the next random piece void nextpiece(void) { random = (TCNT1L<<5)>>5; //random = (TCNT0<<5)>>5; //previous random number generator next = random; //next piece is this random number drawnextpiece(); //draw the next piece to the lcd screen } //draw the next piece to the lcd screen void drawnextpiece(void) { //draw next piece, i.e. the 16 bit values of either 1 or 0 for(k=0;k<4;k++){ for(kk=0;kk<4;kk++){ tbit = (piece[next][0]<< ((4*k)+kk))>> 15; if (tbit == 1) drawBox(NextPieceAddr+(2*kk)+(2*0xF0*k)); else drawNoBox(NextPieceAddr+(2*kk)+(2*0xF0*k)); } } } //for moving left/right update the screen, thus when moving right and left //we want to "delete" the blocks as it moves left/right across the screen //normal upatesdisplay() does not update this address locations //this gets rid of block remanents from the piece being moved to quickly //accross the screen. void updateprevious(void) { //want to update the lines at current to current +6 for (k=0;k<7;k++) { if (k<4) //values where the piece is include the piece in the update { templine1 = (board[current+k] | (((piece[p][t]>>(k*4))<<12)>>index)); } else //value above the piece just include the board and "rewrite" 0's over //where the piece used to be. { templine1 = board[current+k]; } //set all the values to either 0 or 1. for (kk=0;kk<12;kk++) { tbit = ((templine1<<kk)>>15); if ((19-(current+k)) <= 19 && ((kk)-1) < 10) //was11 { address = 0x3C0+(19-(current+k))*2*0xf0+((kk)-1)*2; if (tbit == 1) { drawBox(address); } else drawNoBox(address); } } } } //on gameover we need to draw all boxes to the screen //and then display the message void gameover(void) { for (k=0;k<20;k++) //set the board to all 1's and draw it to the screen { board[k] = 0b1111111111111111;//0b1111111111000000; line = k; drawline(); } //zero out the middle area so that we can display visible text board[9] = 0; line = 9; drawline(); board[10] = 0; line = 10; drawline(); board[11] = 0; line = 11; drawline(); board[12] = 0; line = 12; drawline(); //if winflag, i.e. in two player mode display you win if(winflag == 1) {   Build your own community today with the largest message board hosting company. |