//filename: pool_final.c #include #include #include #include #include #include #include //timeout values for each task #define t1 100 //calculating actual game parameters #define t2 33 //for getting ADC inputs #define ballsInit 15 //game definitions #define dt 5 //float2long(0.02) //time we are running this function (10 ms in this case) #define drag 3 //float2long(0.02) //inches per sec squared #define diameter3 50 #define impactdur 256 //float2long(1.0) #define two 4000 #define onePointOne 140 //282 #define zeroPointFive 200 //128 #define samNo 30 //state machine #define intro 1 //used for the introductory screen #define players 2 //used to select between training or full game modes #define cuestick 3 //use to shoot the cueball #define whiteball 4 //state where cueball has not hit anything yet #define ballbreak 5 //used to pseudo break the balls initially #define ballhit 6 //when the cueball hits someball #define training 7 //used to choose the number of balls #define ballpos 8 //used to position training balls #define ballScratch 9 //for moving the cueball around when its scratched #define gameOver 10 //when the game is over #define xtablemaxLong (xtablemax << 8) //convert table limits to longs #define ytablemaxLong (ytablemax << 8) #define xtableminLong (xtablemin << 8) #define ytableminLong (ytablemin << 8) #define pocket (11 << 8) //size of pocket is 11 pixels, changed to long #define rotDiv 2*PI / (float)rotaryMax //different macros to convert to longs #define mfix(a,b) ((long)((((long)(a))*((long)(b)))>>8)) #define msq(a) ((long)((((long)(a))*((long)(a)))>>8)) #define float2long(a) (long)(a*256) #define long2float(a) (((float)(a))/256.0) #define longPI 0x00000324 //PI in LONG #define longPIo2 0x00000192 //PI over 2 in LONG #define overPI 0x0000394b //180 degrees divide by PI, then multiplied by 256 into a long #define c_angle(a) (int)((mfix((long)((fabs(a))*256),overPI)+0x00000080)>>8) //actual number placed in table, rounded and shifted by 8 #define cosT(a) cosTable[c_angle(a)] //***************************************************** //Game functions void initialize(void); //for initializing void playerName(unsigned char who); //for writing the name of the player void playgame(void); //the main state machine void hitTable(void); //used to check if the table is hit void drawBall7x7(long x,long y,char ballNo,char draw); //for drawing and undrawing the ball void drawCue(long x,long y,int rotaryADC,int cueTip, char draw); //used to draw the cue void drawDotCue(long xpos,long ypos,int rotaryADC,char draw); //draw the dotted lines for the ball dirn //ADC reading system void readADCs(void); //each ball has these variables typedef struct{ float theta; //angle of the ball long newx, x; //the new position of x, and previous x position long newy, y; //the new position of y, and previous y position long v,vx,vy; //overall velocity of the ball, and also in x and y dirns long accelx,accely; //initial acceleration of the ball char in_hole; //tells whether the ball in in the hole or not } Ball; Ball ball[16]; //initiate structure of 16 balls //Global variables unsigned int time1,time2; //for the timer0 unsigned char reload; //timer0 reload to set 1 mSec unsigned char state; //to track the states unsigned char mode; //switching between training or full mode unsigned char ballsPlayed; //the total balls being played unsigned char WHO; //which player's turn //to keep track if new balls are entered unsigned char TotalBallsIn, P1BallsOld,P1BallsNew, P2BallsOld,P2BallsNew; //flags bit firstHit,scratchy; //to know if it is the first hit, to know if white ball scratched bit ownIn, opponentIn; //to track if you hit in your own ball bit cleanmess; //used to clear unwanted spots bit impactflag; //used to know if impact was made unsigned char flag; //sensor variables unsigned int accel_data; //grabs the acceleration data from accelerometer unsigned int linear_adc; //used to get the linear potentiometer's reading unsigned int rotary_adc; //used to get the rotary potentiometer's reading long maxaccel,minaccel,accel_rem; //find the maximum and minimum acceleration, remember the accel used only for ballbreak unsigned int samples[samNo]; //store the previous 'samNo' of acceleration data unsigned char scnt; //used as a counter for the samples taken //Ball variables int rotaryADC; //get a static rotary ADC reading int cueTip; //determine where the tip of the cue is long a; //for the acceleration from the cue float cue_theta,phi,psi; //angle of cue, impact variables for ball unsigned char delayT,delayTB,delayC,delayB; //different delay systems to slow things down unsigned char moving; //tracks the ball to be moved //************************************************************ //ADC readings void readADCs(void) begin unsigned int adc_data1,adc_data2,adc_data; time2=t2; adc_data2 = ADCL; adc_data1 = ADCH; //take in 8 bits to rightmost side of 16bit int adc_data = ((unsigned int)adc_data1) << 8; //shift the 8 bits of ADCH into the top 8 bits, '0's shifted into right hand side adc_data = adc_data | ((unsigned int)adc_data2); //bit-wise OR the 16 bit int with 8 bit char adc_data = adc_data >> 6; //get integer value of adc_data if((ADMUX & 0x1f) == 0) //reading differential ADC0 and ADC1 inputs begin accel_data=adc_data; ADMUX &= 0xe0; ADMUX |= 0x02; //go to read linear pot end else if((ADMUX & 0x1f) == 2) begin linear_adc=adc_data; //finding linear value, changes cueTip ADMUX &= 0xe0; ADMUX |= 0x03; //go to read rotation end else if((ADMUX & 0x1f) == 3) begin rotary_adc=adc_data; //finding rotation, center at 90 degrees from center ADMUX &= 0xe0; ADMUX |= 0x00; //go to read accelaration1 end ADCSRA= ADCSRA | 0x40; //allow interrupts to occur end //************************************************************ //the actual game being run void playgame(void) begin unsigned char cnt1,cnt2; //internal counters unsigned int cnt; //internal counter, this own counts more than 255 unsigned char n; //internal counter long diffX, diffY; //for finding the differences and squares of it long sumspeed; //used for finding the sum of all balls, to see if they are slow enough int i, k, j, m; //??? unsigned int addr,total_samples; //address to move cursor to, count the total sum of samples time1=t1; //reset the timer //main state machine switch(state) begin case intro: begin if(PINB.2==0) //right button pressed begin MoveCursor(380); for(cnt=0;cnt<255;cnt++) //clear all old data begin WriteCommand(MWRITE); WriteData(' '); end MoveCursor(177); //draw the arrow for the next state strcpyf(strbuffer,"->"); WriteString(strbuffer); firstHit=1; //initialize, to be used for ballbreak state state=players; //go to the choosing of mode end end //end intro break; case players: begin //write the different modes possible strcpyf(strbuffer, "Choose Mode"); MoveCursor(140); WriteString(strbuffer); strcpyf(strbuffer, "Training"); MoveCursor(180); WriteString(strbuffer); strcpyf(strbuffer, "Full Game"); MoveCursor(220); WriteString(strbuffer); if(PINB.0==0) //arrow to go down begin MoveCursor(177); strcpyf(strbuffer," "); WriteString(strbuffer); MoveCursor(217); strcpyf(strbuffer,"->"); WriteString(strbuffer); mode=1; //switch between modes end else if(PINB.1==0) //arrow to go up begin MoveCursor(177); strcpyf(strbuffer,"->"); WriteString(strbuffer); MoveCursor(217); strcpyf(strbuffer," "); WriteString(strbuffer); mode=0; //switch between modes end else if(PINB.7==0) //OK button begin MoveCursor(140); for(cnt=0;cnt<130;cnt++) begin WriteCommand(MWRITE); //clear the words WriteData(' '); end if(mode==0) //go to the next state depending on what was chosen begin drawCue(ball[0].x,ball[0].y,rotaryADC,cueTip,0); //undraw the cue ballsPlayed=2; //default setting of training is 2 balls state=training; WHO=1; //play with yourself (player 1) end else begin ballsPlayed=ballsInit; //play the full set of balls state=cuestick; WHO=1; //player 1 to test shooting first end end end //end players state break; case training: begin strcpyf(strbuffer, "Choose number"); MoveCursor(220); WriteString(strbuffer); strcpyf(strbuffer, "of Balls"); MoveCursor(260); WriteString(strbuffer); strcpyf(strbuffer, "Press Up/Down"); MoveCursor(300); WriteString(strbuffer); strcpyf(strbuffer, "to adjust"); MoveCursor(340); WriteString(strbuffer); sprintf(strbuffer,"%d balls ",ballsPlayed); //number of balls in play MoveCursor(420); WriteString(strbuffer); if(PINB.1==0) begin if(++delayB>5) //delay system to slow it down begin delayB=0; if(ballsPlayed<5) //to limit it to the max no. of balls ballsPlayed++; else ballsPlayed=5; end end else if(PINB.0==0) begin if(++delayB>5) //delay system to slow it down begin delayB=0; if(ballsPlayed>1) //to limit it to the min no. of balls ballsPlayed--; else ballsPlayed=1; end end else if(PINB.2==0) //right button, to go to the next state begin MoveCursor(220); for(cnt=0;cnt<160;cnt++) begin WriteCommand(MWRITE); //clear words WriteData(' '); end MoveCursor(420); for(cnt=0;cnt<10;cnt++) begin WriteCommand(MWRITE); //clear words WriteData(' '); end for(cnt=0;cnt<=ballsInit;cnt++) //clear all balls that were initiated drawBall7x7(ball[cnt].x,ball[cnt].y,cnt,0); ball[0].x=80<<8; ball[0].y=70<<8; ball[1].x=50<<8; ball[1].y=70<<8; ball[2].x=40<<8; ball[2].y=40<<8; ball[3].x=40<<8; ball[3].y=110<<8; ball[4].x=30<<8; ball[4].y=20<<8; ball[5].x=30<<8; ball[5].y=120<<8; for(cnt=0;cnt<=ballsPlayed;cnt++) //draw the balls that will be played begin drawBall7x7(ball[cnt].x,ball[cnt].y,cnt,1); ball[cnt].newx=ball[cnt].x; ball[cnt].newy=ball[cnt].y; end moving=0; state=ballpos; end //end right button end //end training state break; case ballpos: begin strcpyf(strbuffer, "Move Ball till"); MoveCursor(220); WriteString(strbuffer); strcpyf(strbuffer, "ready, then press OK"); MoveCursor(260); WriteString(strbuffer); sprintf(strbuffer,"no. %d ball moving ",moving); //number of balls in play MoveCursor(420); WriteString(strbuffer); if(PINB.2==0) //move ballright begin if(ball[moving].x < (xtablemaxLong-(3<<8) )) ball[moving].newx=ball[moving].x + (384); //move 1.5 pixels else ball[moving].newx= (xtablemaxLong-(3<<8) ); end else if(PINB.3==0) //move ball left begin if(ball[moving].x > (xtableminLong+(3<<8) )) ball[moving].newx=ball[moving].x - (384); else ball[moving].newx= (xtableminLong+(3<<8) ); end if(PINB.0==0) //move ball down begin if(ball[moving].y < (ytablemaxLong-(3<<8) )) ball[moving].newy=ball[moving].y + (384); else ball[moving].newy= (ytablemaxLong-(3<<8) ); end else if(PINB.1==0) //move ball up begin if(ball[moving].y > (ytableminLong+(3<<8) )) ball[moving].newy=ball[moving].y - (384); else ball[moving].newy= (ytableminLong+(3<<8) ); end for(cnt=0;cnt<=ballsPlayed;cnt++) //clear all balls that were initiated drawBall7x7(ball[cnt].x,ball[cnt].y,cnt,0); ball[moving].x=ball[moving].newx; ball[moving].y=ball[moving].newy; for(cnt=0;cnt<=ballsPlayed;cnt++) //draw the balls that will be played drawBall7x7(ball[cnt].newx,ball[cnt].newy,cnt,1); if(PINB.6==0) //next ball begin if(++delayB>5) //delay system to slow it down begin delayB=0; if(moving= (samNo)) scnt=0; //reset the samples drawCue(ball[0].x,ball[0].y,rotaryADC,cueTip,1); //draw the new cue with the changed parameters drawDotCue(ball[0].x,ball[0].y,rotaryADC,1); maxaccel=300; minaccel=700; //reset the test variables for(cnt=0;cnt maxaccel) //grab the maximum acceleration of the cue maxaccel=samples[cnt]; if( (samples[cnt]) < minaccel) minaccel=samples[cnt]; end playerName(WHO); //display the player name, WHO is to be updated from other states if(cueTip <= 10) //touched the ball begin total_samples=0; for(scnt=0;scnt50) //redraw everything begin delayT=0; DrawTable(); //drawtable end if(++delayTB>7) //redraw everything begin delayTB=0; for(cnt=0;cnt<=ballsPlayed;cnt++) begin drawBall7x7(ball[cnt].x,ball[cnt].y,cnt,0); //refresh all balls every 15th time if(ball[cnt].in_hole==0) drawBall7x7(ball[cnt].x,ball[cnt].y,cnt,1); end end end //end cuestick break; case whiteball: begin drawBall7x7(ball[0].x,ball[0].y,0,0); //undraw ball if ((impactflag==0) && (ball[0].v>0)) begin ball[0].v = labs(ball[0].v - mfix(drag,ball[0].v)); //got to define drag later if(ball[0].v < two) ball[0].v=0; ball[0].vx = mfix(ball[0].v, cosT(ball[0].theta) ); ball[0].vy = mfix(-ball[0].v, float2long(sin(ball[0].theta)) ); end if (impactflag == 1) //this is for the first movement of the cue ball begin //on impact with the cue stick. it is initialized to 1. ball[0].theta = cue_theta; ball[0].accelx = mfix(a, cosT(ball[0].theta) ); ball[0].accely = mfix(-a, float2long(sin(ball[0].theta)) ); ball[0].v = labs(mfix(impactdur,a)); //duration of impact not yet determined. to be tweaked around ball[0].vx = mfix(impactdur,ball[0].accelx); ball[0].vy = mfix(impactdur,ball[0].accely); impactflag=0; end ball[0].newx = (ball[0].x + mfix(ball[0].vx,dt)); //new temporary x position ball[0].newy = (ball[0].y + mfix(ball[0].vy,dt)); //new temporary y position //reflection off the walls...taken from code of bouncing ball hitTable(); for (n=1;n<=ballsPlayed;n++) //collision detection with the other balls begin if(ball[n].in_hole == 0) begin diffX=0; //reset diffX diffX=labs(ball[0].newx - ball[n].x); diffX=(labs( (mfix(diffX,diffX)) ))>>8; //make them into actual numbers diffY=0; //reset diffY diffY=labs(ball[0].newy - ball[n].y); diffY=(labs( (mfix(diffY,diffY)) ))>>8; //make them into actual numbers //less costly to do the subtraction once instead of twice //do not use sqrt to calculate, use squares of everything if ( (diffX + diffY ) <= diameter3 ) //using pythagoras theorem begin // to prevent 2 balls from overlapping if((firstHit==1) && (ballsPlayed==15)) begin firstHit=0; //reset firstHit flag state=ballbreak; end else begin if(mode==1) begin if( ((n<8) && (WHO==2)) || ((n>8) && (WHO==1)) ) //hit opponents ball with white ball scratchy=1; //only activate scratchy if in full game mode end state=ballhit; end ball[0].newx = ball[0].x; //backtrack to the old position ball[0].newy = ball[0].y; end //end if collision part end //end test for in hole end //end for loop if(ball[0].in_hole != 1) //only draw ball if its not in the hole drawBall7x7(ball[0].newx,ball[0].newy,0,1); ball[0].x=ball[0].newx; //update ball position ball[0].y=ball[0].newy; if (ball[0].v==0) begin if(mode==1) //playing full game begin if(WHO==1) WHO=2; //switch players else if(WHO==2) WHO=1; end state=ballScratch; impactflag=1; end //end cueball velocity==0 end break; case ballScratch: begin strcpyf(strbuffer, "Place white ball"); MoveCursor(540); WriteString(strbuffer); strcpyf(strbuffer, "using buttons"); MoveCursor(580); WriteString(strbuffer); playerName(WHO); //displays the player who is to adjust the white ball if(PINB.2==0) //move right begin if(ball[0].x < (xtablemaxLong-(3<<8) )) ball[0].newx=ball[0].x + (384); //move 1.5 pixels else ball[0].newx= (xtablemaxLong-(3<<8) ); end else if(PINB.3==0) //move left begin if(ball[0].x > (xtableminLong+(3<<8) )) ball[0].newx=ball[0].x - (384); else ball[0].newx= (xtableminLong+(3<<8) ); end if(PINB.0==0) //move down begin if(ball[0].y < (ytablemaxLong-(3<<8) )) ball[0].newy=ball[0].y + (384); else ball[0].newy= (ytablemaxLong-(3<<8) ); end else if(PINB.1==0) //move up begin if(ball[0].y > (ytableminLong+(3<<8) )) ball[0].newy=ball[0].y - (384); else ball[0].newy= (ytableminLong+(3<<8) ); end if(PINB.7==0) //ok button begin MoveCursor(500); for(cnt=0;cnt<120;cnt++) begin WriteCommand(MWRITE); WriteData(' '); end scratchy=0; state=cuestick; ball[0].in_hole=0; end drawBall7x7(ball[0].x,ball[0].y,0,0); //undraw and draw new position of the ball drawBall7x7(ball[0].newx,ball[0].newy,0,1); ball[0].x=ball[0].newx; //update new position of ball ball[0].y=ball[0].newy; if(++delayT>10) //redraw the table begin delayT=0; DrawTable(); for(cnt=1;cnt<=ballsPlayed;cnt++) begin drawBall7x7(ball[cnt].x,ball[cnt].y,cnt,0); //refresh all balls every 15th time if(ball[cnt].in_hole==0) drawBall7x7(ball[cnt].x,ball[cnt].y,cnt,1); end end end break; case ballbreak: begin for(cnt=0;cnt<=ballsInit;cnt++) //undraw all the balls drawBall7x7(ball[cnt].x,ball[cnt].y,cnt,0); //ball[0].x=97;ball[0].y=66; //let ball0 move freely ball[1].x=85;ball[1].y=65; //initiate the positions of all the ball ball[2].x=77;ball[2].y=71; ball[3].x=69;ball[3].y=58; ball[4].x=61;ball[4].y=63; ball[5].x=61;ball[5].y=79; ball[6].x=52;ball[6].y=51; ball[7].x=50;ball[7].y=78; ball[8].x=68;ball[8].y=66; ball[9].x=77;ball[9].y=59; ball[10].x=71;ball[10].y=83; ball[11].x=61;ball[11].y=54; ball[12].x=61;ball[12].y=70; ball[13].x=53;ball[13].y=57; ball[14].x=50;ball[14].y=71; ball[15].x=50;ball[15].y=85; if(accel_rem > 530) begin //ball[0].v=7; ball[0].theta=0; ball[1].v=7; ball[1].theta=0.1*PI; ball[2].v=5; ball[2].theta=1.75*PI; ball[3].v=4; ball[3].theta=0.4*PI; ball[4].v=2; ball[4].theta=0.9*PI; ball[5].v=5; ball[5].theta=1.5*PI; ball[6].v=4; ball[6].theta=0.7*PI; ball[7].v=4; ball[7].theta=PI; ball[8].v=1; ball[8].theta=PI; ball[9].v=5; ball[9].theta=0.25*PI; ball[10].v=5; ball[10].theta=1.5*PI; ball[11].v=3; ball[11].theta=0.85*PI; ball[12].v=2; ball[12].theta=1.2*PI; ball[13].v=3; ball[13].theta=0.9*PI; ball[14].v=5; ball[14].theta=PI; ball[15].v=6; ball[15].theta=1.3*PI; end else begin //ball[0].v=7; ball[0].theta=0; ball[1].v=4; ball[1].theta=0.15*PI; ball[2].v=4; ball[2].theta=1.7*PI; ball[3].v=3; ball[3].theta=0.45*PI; ball[4].v=1; ball[4].theta=0.95*PI; ball[5].v=2; ball[5].theta=1.15*PI; ball[6].v=3; ball[6].theta=0.75*PI; ball[7].v=2; ball[7].theta=1.05*PI; ball[8].v=0; ball[8].theta=PI; ball[9].v=4; ball[9].theta=0.2*PI; ball[10].v=3; ball[10].theta=1.65*PI; ball[11].v=2; ball[11].theta=0.8*PI; ball[12].v=1; ball[12].theta=1.25*PI; ball[13].v=2; ball[13].theta=0.85*PI; ball[14].v=2; ball[14].theta=1.05*PI; ball[15].v=3; ball[15].theta=1.25*PI; end // for(cnt=0;cnt<=ballsPlayed;cnt++) //draw the balls in new positions // drawBall7x7(ball[cnt].x,ball[cnt].y,cnt,1); for(cnt=1;cnt<=ballsPlayed;cnt++) //transform the values into longs begin ball[cnt].x <<= 8; //make into a long ball[cnt].y <<= 8; //make into a long ball[cnt].v <<= 13; ball[cnt].vx = mfix(ball[cnt].v, cosT(ball[cnt].theta) ); ball[cnt].vy = mfix(-ball[cnt].v, float2long(sin(ball[cnt].theta)) ); drawBall7x7(ball[cnt].x,ball[cnt].y,cnt,1); //draw these balls end for (i=0;i<=ballsPlayed;i++) begin ball[i].newx = (ball[i].x + mfix(ball[i].vx,dt)); //new temporary x position ball[i].newy = (ball[i].y + mfix(ball[i].vy,dt)); //new temporary y position drawBall7x7(ball[i].x,ball[i].y,i,0); if(ball[i].in_hole == 0) drawBall7x7(ball[i].newx,ball[i].newy,i,1); end cleanmess=1; //flag to clean the pixels left behind state=ballhit; //go into ball hit state immediately end break; case ballhit: // remain in this state till all 16 balls have 0 velocity begin for ( i=0;i<=ballsPlayed;i++) begin if ( (labs(ball[i].v)) >0) //absolute value of velocity is positive begin ball[i].v = labs(ball[i].v - mfix(drag,ball[i].v)); //got to define drag later if(ball[i].v < two) ball[i].v=0; //if its too slow, make the velocity zero ball[i].vx = mfix(ball[i].v, cosT(ball[i].theta) ); ball[i].vy = mfix(-ball[i].v, float2long(sin(ball[i].theta)) ); end ball[i].newx = (ball[i].x + mfix(ball[i].vx,dt)); //new temporary x position ball[i].newy = (ball[i].y + mfix(ball[i].vy,dt)); //new temporary y position //check if it has hit the table or gone into the pocket hitTable(); if (i==0) k=1; //to ensure that i and k are never the same in an iteration else k=0; while (k<=ballsPlayed) begin if (k==i) k++; if ((k==i+1) && (k==16)) break; //break out of the while loop if( (ball[i].in_hole==0) && (ball[k].in_hole==0) ) begin diffX=0; //reset diffX diffX=labs(ball[i].newx - ball[k].x); diffX=(labs( (mfix(diffX,diffX)) ))>>8; //make them into actual numbers diffY=0; //reset diffY diffY=labs(ball[i].newy - ball[k].y); diffY=(labs( (mfix(diffY,diffY)) ))>>8; //make them into actual numbers if ( (diffX + diffY ) <= diameter3 ) //using pythagoras theorem begin phi = atan2(-long2float(ball[i].y - ball[k].y), long2float(ball[i].x - ball[k].x) ); //calculating angles for elastic collision ball[k].theta=PI+phi; psi= ball[k].theta - ball[i].theta; ball[i].theta=PI/2.0+phi; ball[k].v = labs(mfix(ball[i].v, cosT(psi) )); ball[i].v = labs(-mfix(ball[i].v, float2long(sin(psi)) )); ball[k].vx = mfix(ball[k].v, cosT(ball[k].theta) ); ball[k].vy = mfix(-ball[k].v, float2long(sin(ball[k].theta)) ); ball[i].vx = mfix(ball[i].v, cosT(ball[i].theta) ); ball[i].vy = mfix(-ball[i].v, float2long(sin(ball[i].theta)) ); ball[i].newx = (ball[i].x + mfix(ball[i].vx,dt)); //new temporary x position ball[i].newy = (ball[i].y + mfix(ball[i].vy,dt)); //new temporary y position end //end collision end //end test for in_hole k++; end// end while loop drawBall7x7(ball[i].x,ball[i].y,i,0); //erase the balldraw it only if its not in the pocket if(ball[i].in_hole == 0) drawBall7x7(ball[i].newx,ball[i].newy,i,1); //draw it only if its not in the pocket //end ball[i].x=ball[i].newx; ball[i].y=ball[i].newy; end //end for loop for i sumspeed=0; //initialize the sumspeed calculation for ( m=0;m<=ballsPlayed;m++) sumspeed += labs(ball[m].v); //find total speed of all the balls if (sumspeed == 0) begin impactflag=1; i=0; k=0; j=0; m=0; if(scratchy==1) state=ballScratch; else if(WHO==1) begin if( (ownIn==1) && (opponentIn==0) ) ; //same player else WHO=2; //all other cases, change player ownIn=0; opponentIn=0; //reset flags state=cuestick; //always go back to cuestick end else if(WHO==2) begin if( (ownIn==1) && (opponentIn==0) ) ; //same player else WHO=1; //all other cases, change player ownIn=0; opponentIn=0; //reset flags state=cuestick; //always go back to cuestick end drawBall7x7(ball[0].x,ball[0].y,0,0); drawBall7x7(ball[0].newx,ball[0].newy,0,1); end //end sumspeed if(cleanmess==1) begin // address=1000+(40*(ymin7 +y-3))+((int)(xmin7 +x-3) / 8); //#define xmin7 12 //starting x position of ball on table (allowable) //#define xmax7 284 //ending x position of ball on table (allowable) //midpoint is 136 //#define ymin7 17 //starting y position of ball on table (allowable) //#define ymax7 149 //ending y position of ball on table (allowable) addr=1000+(40*(64))+(7); //3567 for(cnt1=0;cnt1<80;cnt1++) begin for(cnt2=0;cnt2<10;cnt2++) begin MoveCursor(addr); WriteCommand(MWRITE); WriteData(0x00); addr++; end addr+=40; end end if(++delayC>5) begin delayC=0; cleanmess=0; end end //end state of ballhit break; case gameOver: begin strcpyf(strbuffer, "GAMEOVER"); MoveCursor(457); WriteString(strbuffer); end break; end //end switch statement MoveCursor(840); //367 initially sprintf(strbuffer,"tip:%d Rot:%d Accel:%d S:%d ",(int)cueTip,(int)rotary_adc,(int)accel_data,state); WriteString(strbuffer); MoveCursor(880); //367 initially ftoa(ball[0].vx>>8,1,strbuffer); WriteString(strbuffer); MoveCursor(890); //367 initially ftoa(ball[0].vy>>8,1,strbuffer); WriteString(strbuffer); // MoveCursor(900); //367 initially // ftoa(sumspeed>>8,1,strbuffer); // WriteString(strbuffer); MoveCursor(920); //367 initially ftoa(ball[0].v>>8,1,strbuffer); WriteString(strbuffer); MoveCursor(930); //367 initially sprintf(strbuffer,"A mem: %i ", accel_rem); WriteString(strbuffer); MoveCursor(940); //367 initially sprintf(strbuffer,"A: %i ", maxaccel); WriteString(strbuffer); end //end playgame //************************************************************* void main(void) begin cueTip=15; //15 pixels from the center of the cue ball, adjusted by ADC rotaryADC=15; //out of 1024, center is x-axis horizontal initialize(); GameInit(); while (1) begin if(time1==0) playgame(); if(time2==0) readADCs(); end end //end main //************************************************************* interrupt [TIM0_OVF] void timer0_overflow(void) begin TCNT0 = reload; if(time1>0) --time1; if(time2>0) --time2; end //************************************************************* // GameInit() initializes players at start of game void GameInit(void) begin unsigned char cnt; MoveCursor(5); strcpyf(strbuffer, "BY: DANNY CHOW & "); WriteString(strbuffer); strcpyf(strbuffer, "ANTHONY TAY"); WriteString(strbuffer); strcpyf(strbuffer, "Welcome to"); MoveCursor(380); //367 initially WriteString(strbuffer); strcpyf(strbuffer, "Interactive Pool"); MoveCursor(457); WriteString(strbuffer); strcpyf(strbuffer, "in a box"); MoveCursor(541); WriteString(strbuffer); strcpyf(strbuffer, "Press -> to continue"); MoveCursor(614); WriteString(strbuffer); ball[0].x=100; //initial x and y position of the cue ball on the screen ball[0].y=65; ball[1].x=82;ball[1].y=65; //initiate the positions of all the ball ball[2].x=75;ball[2].y=69; ball[3].x=68;ball[3].y=59; ball[4].x=61;ball[4].y=63; ball[5].x=61;ball[5].y=77; ball[6].x=54;ball[6].y=53; ball[7].x=54;ball[7].y=74; ball[8].x=68;ball[8].y=66; ball[9].x=75;ball[9].y=62; ball[10].x=68;ball[10].y=73; ball[11].x=61;ball[11].y=56; ball[12].x=61;ball[12].y=70; ball[13].x=54;ball[13].y=60; ball[14].x=54;ball[14].y=67; ball[15].x=54;ball[15].y=81; for(cnt=0;cnt<=ballsInit;cnt++) begin ball[cnt].x <<= 8; //make into a long ball[cnt].y <<= 8; //make into a long drawBall7x7(ball[cnt].x,ball[cnt].y,cnt,1); end drawCue(ball[0].x,ball[0].y,rotaryADC,cueTip,1); //draw the initial cue position end //*********************************************************** //detects ball hitting the table void hitTable(void) begin unsigned char cnt,cntB; for(cnt=0;cnt<=ballsPlayed;cnt++) begin //xtablemaxLong (long)((int)272<<8) //if its in the hole, there's no more collission detection to be considered if(ball[cnt].in_hole == 0) begin //detects collision with right side of the table if ( (ball[cnt].newx >= xtablemaxLong ) && (ball[cnt].newy > pocket) && (ball[cnt].newy < (ytablemaxLong-pocket)) ) begin ball[cnt].vx = ball[cnt].vx*-1; ball[cnt].newx = (xtablemaxLong)-(1<<8); ball[cnt].theta=PI-ball[cnt].theta; end //detects collision with left side of the table else if ( (ball[cnt].newx <= xtableminLong) && (ball[cnt].newy > pocket) && (ball[cnt].newy < (ytablemaxLong-pocket)) ) begin ball[cnt].vx = ball[cnt].vx*-1; ball[cnt].newx = 1<<8; ball[cnt].theta=PI-ball[cnt].theta; end //detects collision with top left side of table else if ( (ball[cnt].newy <= ytableminLong) && (ball[cnt].newx > pocket) && (ball[cnt].newx < ( (xtablemaxLong-pocket) >> 1) ) ) begin ball[cnt].vy = ball[cnt].vy*-1; ball[cnt].newy = 1<<8; ball[cnt].theta=2*PI-ball[cnt].theta; end //detects collision with top right side of table else if ( (ball[cnt].newy <= ytableminLong) && (ball[cnt].newx > ( (xtablemaxLong+pocket) >> 1)) && (ball[cnt].newx < (xtablemaxLong-pocket) ) ) begin ball[cnt].vy = ball[cnt].vy*-1; ball[cnt].newy = 1<<8; ball[cnt].theta=2*PI-ball[cnt].theta; end //detects collision with bottom left side of table else if ( (ball[cnt].newy >= (ytablemaxLong)) && (ball[cnt].newx > pocket) && (ball[cnt].newx < ( (xtablemaxLong-pocket) >> 1) ) ) begin ball[cnt].vy = ball[cnt].vy*-1; ball[cnt].newy = (ytablemaxLong)-(1<<8); ball[cnt].theta=2*PI-ball[cnt].theta; end //detects collision with bottom right side of table else if ( (ball[cnt].newy >= (ytablemaxLong)) && (ball[cnt].newx > ( (xtablemaxLong+pocket) >> 1)) && (ball[cnt].newx < (xtablemaxLong-pocket) ) ) begin ball[cnt].vy = ball[cnt].vy*-1; ball[cnt].newy = (ytablemaxLong)-(1<<8); ball[cnt].theta=2*PI-ball[cnt].theta; end else if( (ball[cnt].newx >= xtableminLong) && (ball[cnt].newx <= xtablemaxLong) && (ball[cnt].newy >= ytableminLong) && (ball[cnt].newy <= ytablemaxLong) ) ; //do nothing, leave it if it is in the table within limits //gone into a pocket else begin drawBall7x7(ball[cnt].newx,ball[cnt].newy,cnt,0); //undraw ball ball[cnt].in_hole=1; //gone into a pocket ball[cnt].vx=0; ball[cnt].vy=0; ball[cnt].v=0; if(mode==1) begin if(WHO==1) //check if player1 enters own balls or opponent's balls begin if(cnt<8) begin ownIn=1; end else if(cnt>8) begin opponentIn=1; end else if(cnt==8) begin P1BallsNew=0; for(cntB=1;cntB<8;cntB++) P1BallsNew += ball[cntB].in_hole; if(P1BallsNew != 7) begin WHO=4; state=gameOver; //gameover if 8th ball entered in end else begin WHO=3; state=gameOver; end end end else if(WHO==2) //check if player2 enters own balls or opponent's balls begin if(cnt>8) begin ownIn=1; end else if(cnt<8) begin opponentIn=1; end else if(cnt==8) begin P2BallsNew=0; for(cntB=1;cntB<8;cntB++) P2BallsNew += ball[cntB].in_hole; if(P2BallsNew != 7) begin WHO=3; state=gameOver; //gameover if 8th ball entered in end else begin WHO=4; state=gameOver; end end end end //end mode check for full game if(cnt==0) begin scratchy=1; ball[0].x=140<<8; //set ball position ball[0].y=70<<8; strcpyf(strbuffer, "Ball Scratched"); MoveCursor(500); WriteString(strbuffer); end else begin drawHoleBall(cnt); //draw ball end //end cnt==0 end //end else for table end //end for if(not in hole) end //end for loop end //end function //************************************************************* //draws the moving cue void drawCue(long xpos,long ypos,int rotaryADC,int cueTip,char draw) //takes in values of the cue ball and ADC reading begin //cueTip is the actual value, not shifted int cueXstart,cueYstart,cueXend,cueYend,slope; float xratio,yratio; int x,y; cueTip -= 6; x=(int)(xpos>>8); y=(int)(ypos>>8); xratio= cos( ((float)rotaryADC )*rotDiv); yratio= sin( ((float)rotaryADC )*rotDiv); cueXstart= x+xmin7 + (int)(cueTip*xratio); cueYstart= y+ymin7 + (int)(cueTip*yratio); cueXend= x + xmin7+ (int)( (cueTip+cueLength) * xratio); cueYend= y + ymin7+ (int)( (cueTip+cueLength) * yratio); slope=(cueYend-cueYstart)/(cueXend-cueXstart); if(cueXend > 320) cueXend=320; //limit it to end of screen else if(cueXend < 0) cueXend=0; drawLine(cueXstart,cueYstart,cueXend,cueYend,draw); end //************************************************************* //draws the moving cue void drawDotCue(long xpos,long ypos,int rotaryADC,char draw) //takes in values of the cue ball and ADC reading begin //cueTip is the actual value, not shifted #define segments 12 int cueXstart[segments],cueYstart[segments],cueXend[segments],cueYend[segments]; float xratio,yratio; int x,y; unsigned char cnt; x=(int)(xpos>>8); y=(int)(ypos>>8); xratio= cos( PI+ (((float)rotaryADC )*rotDiv) ); yratio= sin( PI+ (((float)rotaryADC )*rotDiv) ); for(cnt=0;cnt 287 || (cueXend[cnt] < 9) || (cueYend[cnt] > 152) || (cueYend[cnt] < 14) ); else drawLine(cueXstart[cnt],cueYstart[cnt],cueXend[cnt],cueYend[cnt],draw); end //end for loop end //************************************************************* // drawBall() draw on side menu depending on State void drawBall7x7(long xpos,long ypos,char ballNo,char draw) begin int address,i; unsigned char shiftball,old_pixel; int x,y; x=(int)(xpos>>8); //make it back into an int y=(int)(ypos>>8 ); //take the center of the board to be x,y if(xxtablemax) x=xtablemax; if(yytablemax) y=ytablemax; shiftball=(x+xmax7-3)%8; //find mod of 8 address=1000+(40*(ymin7 +y-3))+((int)(xmin7 +x-3) / 8); if(address > 1000) begin for (i=0; i<7; i++) begin MoveCursor(address); WriteCommand(MREAD); DDRD=0x00; //set PORTD to be inputs PORTD=0x00; //no pull-ups PORTC=DataRead; delay_us(30); //30 //to wait for data to be read old_pixel=PIND; //get the data back PORTC=LCDnop; //tell the LCD to stop reading the items DDRD=0xff; //set the data C to be outputs delay_us(20); //10 //wait for the LCD to stop old_pixel &= (0xff << (8-shiftball)); MoveCursor(address); WriteCommand(MWRITE); if(draw==1) WriteData( (ball7x7[ballNo][i] >> shiftball) | (old_pixel) ); else WriteData( old_pixel ); if(shiftball > 1) begin MoveCursor(address+1); WriteCommand(MREAD); DDRD=0x00; //set PORTD to be inputs PORTD=0x00; //no pull-ups PORTC=DataRead; delay_us(30); //30 //to wait for data to be read old_pixel=PIND; //get the data back PORTC=LCDnop; //tell the LCD to stop reading the items DDRD=0xff; //set the data C to be outputs delay_us(20); //10 //wait for the LCD to stop old_pixel &= (0xff >> shiftball); MoveCursor(address+1); WriteCommand(MWRITE); if(draw==1) WriteData( ball7x7[ballNo][i] << (8-shiftball) | (old_pixel) ); else WriteData( old_pixel ); end address = address+40; end //end for loop end //end if for address<1000 end //end function //************************************************************ //writes the correct player name void playerName(unsigned char who) begin if(mode==1) //only display in game mode begin if(who==1) begin strcpyf(strbuffer, "Player1's turn"); MoveCursor(740); WriteString(strbuffer); end else if(who==2) begin strcpyf(strbuffer, "Player2's turn"); MoveCursor(740); WriteString(strbuffer); end if(who==3) begin strcpyf(strbuffer, "Player1 won "); MoveCursor(740); WriteString(strbuffer); end else if(who==4) begin strcpyf(strbuffer, "Player2 won "); MoveCursor(740); WriteString(strbuffer); end end //end mode==1 end //************************************************************* void initialize(void) begin unsigned char i; DDRB = 0x00; //input from PINB PORTB= 0xff; //internal pull-up resistor DDRC = 0xff; DDRD = 0xff; // setup timer0 reload = 256 - 125; // value for 2 millisecond TCNT0 = reload; TCCR0 = 3; // prescalar to 64 TIMSK = 1; // turn on timer0 overflow ISR time1=t1; time2=t2; //internal AVCC reference of (5V), Aref not connected,ADLAR=1 right adjust //ADC2 selected ADMUX=0b01100010; //ADC enable, start conversion, not free running, //no interrupts, prescale 64 ->16e6/64=62.5kHz ADCSRA= 0b11000110; //for reading ADC task lcdinit(); DrawTable(); impactflag=1; state=intro; for (i=0;i<=ballsPlayed;i++) begin ball[i].v=0; ball[i].vx=0; ball[i].vy=0; ball[i].accelx=0; ball[i].accely=0; ball[i].in_hole=0; //not in hole at the beginning end // crank up the ISRs #asm sei #endasm end