Full Version : BiLines AVR Tetris Game
avr >>GAME & VIDEO PROJECTS >>BiLines AVR Tetris Game


Admin3- 04-18-2006
Project description:
We decided we wanted to build a Tetris-like game for our final 476 project. We felt this project would challenge our hardware and software skills. We liked the numerous optional features that we could add but were not crucial. For copyright reasons, we decided to change the rules and the pieces from the classic Tetris game and renamed it “BiLines”.

SED1330 LCD

Seiko G321D Graphic module

Link: http://instruct1.cit.cornell.edu/courses/e...s53/Bilines.htm

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) {
   


Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.