//video gen and sound //D.5 is sync:1000 ohm + diode to 75 ohm resistor //D.6 is video:330 ohm + diode to 75 ohm resistor //B.3 is sound and should have a 10k resistor to gnd #pragma regalloc- //I allocate the registers myself #pragma optsize- //optimize for speed #include #include #include #include #include //cycles = 63.625 * 16 Note NTSC is 63.55 //but this line duration makes each frame exactly 1/60 sec //which is nice for keeping a realtime clock #define lineTime 1018 #define begin { #define end } #define ScreenTop 30 #define ScreenBot 230 //NOTE that v1 to v8 and i must be in registers! register char v1 @4; register char v2 @5; register char v3 @6; register char v4 @7; register char v5 @8; register char v6 @9; register char v7 @10; register char v8 @11; register int i @12; #pragma regalloc+ char syncON, syncOFF; int LineCount, time; //animation int v1x, v1y, v2x, v2y,paddle; //x&y velocities for ball 1 & 2 char p1x_move, p2x_move, p1_width, p2_width, avalue, temp, mode, p2y, p1y; char life; //Player 1 position variables int p1_posx @0x72C; //16-bit paddle x position for floating point binary char p1x @0x72D; //8-bit high bit of paddle's x-position //int p1_posy @0x72D; //16-bit paddle y position for floating point binary //char p1y @0x72E; //8-bit high bit of paddle's y-position //Player 2 position variables int p2_posx @0x72E; //16-bit paddle x position for floating point binary char p2x @0x72F; //8-bit high bit of paddle's x-position int x1pos @0x730; //16-bit x position value for floating binary char x1 @0x731; //8-bit high byte of x-position int y1pos @0x732; //16-bit y position value for floating binary char y1 @0x733; //8-bit high byte of y-position int x2pos @0x734; //16-bit x position value for floating binary char x2 @0x735; //8-bit high byte of x-position int y2pos @0x736; //16-bit y position value for floating binary char y2 @0x737; //8-bit high byte of y-position char brick_pos[4][15] @0x738; int power_pos[3][3] @0x774; /***********POWER_POS MATRIX DEFINITION*********************** power_pos[0][0] -> Power-up 0's Enabler power_pos[1][0] -> Power-up 0's x-position power_pos[2][0] -> Power-up 0's y-position power_pos[0][1] -> Power-up 1's Enabler power_pos[1][1] -> Power-up 1's x-position power_pos[2][1] -> Power-up 1's y-position power_pos[0][2] -> Power-up 2's Enabler power_pos[1][2] -> Power-up 2's x-position power_pos[2][2] -> Power-up 2's y-position *************************************************************/ char protect_brick[2][15] @0x786; char screen[1600], t, ts[10]; char sound_counter @0x7A4; int sound_counter2 @0x7A5; char tone @0x7A7; //char temp_mode @0x7A8; //char temp_player @0x7A9; /**************************************** POWER UP 0 - Lengthen Paddle 1 - Point Multiplier 2 - Paddle Gun 3 - (empty) 4 - (empty) ... /*****************************************/ flash char power[3][8]={ //Lengthen paddle (<->) 0b00000000, 0b00000000, 0b00000000, 0b00100100, 0b01000010, 0b11111111, 0b01000010, 0b00100100, //Double score (2x) 0b00000000, 0b00000000, 0b00000000, 0b11100000, 0b00101001, 0b11100110, 0b10000110, 0b11101001, //+1 Life 0b00000000, 0b00000000, 0b10101111, 0b10101101, 0b10101111, 0b10101100, 0b10111100, 0b00000000 }; flash char bricks[8][8]={ //Blank 8x8 Space 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, //Regular Brick 0b00000000, 0b00000000, 0b01111111, 0b01000001, 0b01000001, 0b01111111, 0b00000000, 0b00000000, //Two-Ball 0b00000000, 0b00000000, 0b01111111, 0b01100111, 0b01100111, 0b01111111, 0b00000000, 0b00000000, //Lengthener 0b00000000, 0b00000000, 0b01111111, 0b01111111, 0b01000001, 0b01111111, 0b00000000, 0b00000000, //Point Doubler 0b00000000, 0b00000000, 0b01111111, 0b01101011, 0b01101011, 0b01111111, 0b00000000, 0b00000000, //Unbreakable 0b00000000, 0b00000000, 0b01111111, 0b01111111, 0b01111111, 0b01111111, 0b00000000, 0b00000000, //+1 Life 0b00000000, 0b00000000, 0b01111111, 0b01001001, 0b01011101, 0b01111111, 0b00000000, 0b00000000, //1 0b00000000, 0b00000000, 0b01111111, 0b01110111, 0b01110111, 0b01111111, 0b00000000, 0b00000000 }; //Point plot lookup table //One bit masks flash char pos[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; //define some character bitmaps //5x7 characters flash char bitmap[38][7]={ //0 0b01110000, 0b10001000, 0b10011000, 0b10101000, 0b11001000, 0b10001000, 0b01110000, //1 0b00100000, 0b01100000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b01110000, //2 0b01110000, 0b10001000, 0b00001000, 0b00010000, 0b00100000, 0b01000000, 0b11111000, //3 0b11111000, 0b00010000, 0b00100000, 0b00010000, 0b00001000, 0b10001000, 0b01110000, //4 0b00010000, 0b00110000, 0b01010000, 0b10010000, 0b11111000, 0b00010000, 0b00010000, //5 0b11111000, 0b10000000, 0b11110000, 0b00001000, 0b00001000, 0b10001000, 0b01110000, //6 0b01000000, 0b10000000, 0b10000000, 0b11110000, 0b10001000, 0b10001000, 0b01110000, //7 0b11111000, 0b00001000, 0b00010000, 0b00100000, 0b01000000, 0b10000000, 0b10000000, //8 0b01110000, 0b10001000, 0b10001000, 0b01110000, 0b10001000, 0b10001000, 0b01110000, //9 0b01110000, 0b10001000, 0b10001000, 0b01111000, 0b00001000, 0b00001000, 0b00010000, //A 0b01110000, 0b10001000, 0b10001000, 0b10001000, 0b11111000, 0b10001000, 0b10001000, //B 0b11110000, 0b10001000, 0b10001000, 0b11110000, 0b10001000, 0b10001000, 0b11110000, //C 0b01110000, 0b10001000, 0b10000000, 0b10000000, 0b10000000, 0b10001000, 0b01110000, //D 0b11110000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b11110000, //E 0b11111000, 0b10000000, 0b10000000, 0b11111000, 0b10000000, 0b10000000, 0b11111000, //F 0b11111000, 0b10000000, 0b10000000, 0b11111000, 0b10000000, 0b10000000, 0b10000000, //G 0b01110000, 0b10001000, 0b10000000, 0b10011000, 0b10001000, 0b10001000, 0b01110000, //H 0b10001000, 0b10001000, 0b10001000, 0b11111000, 0b10001000, 0b10001000, 0b10001000, //I 0b01110000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b01110000, //J 0b00111000, 0b00010000, 0b00010000, 0b00010000, 0b00010000, 0b10010000, 0b01100000, //K 0b10001000, 0b10010000, 0b10100000, 0b11000000, 0b10100000, 0b10010000, 0b10001000, //L 0b10000000, 0b10000000, 0b10000000, 0b10000000, 0b10000000, 0b10000000, 0b11111000, //M 0b10001000, 0b11011000, 0b10101000, 0b10101000, 0b10001000, 0b10001000, 0b10001000, //N 0b10001000, 0b10001000, 0b11001000, 0b10101000, 0b10011000, 0b10001000, 0b10001000, //O 0b01110000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b01110000, //P 0b11110000, 0b10001000, 0b10001000, 0b11110000, 0b10000000, 0b10000000, 0b10000000, /* //Q 0b01110000, 0b10001000, 0b10001000, 0b10001000, 0b10101000, 0b10010000, 0b01101000,*/ //Q represents a space 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, //R 0b11110000, 0b10001000, 0b10001000, 0b11110000, 0b10100000, 0b10010000, 0b10001000, //S 0b01111000, 0b10000000, 0b10000000, 0b01110000, 0b00001000, 0b00001000, 0b11110000, //T 0b11111000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, //U 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b01110000, //V 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b01010000, 0b00100000, //W 0b10001000, 0b10001000, 0b10001000, 0b10101000, 0b10101000, 0b10101000, 0b01010000, //X 0b10001000, 0b10001000, 0b01010000, 0b00100000, 0b01010000, 0b10001000, 0b10001000, //Y 0b10001000, 0b10001000, 0b10001000, 0b01010000, 0b00100000, 0b00100000, 0b00100000, //Z 0b11111000, 0b00001000, 0b00010000, 0b00100000, 0b01000000, 0b10000000, 0b11111000, //figure1 0b01110000, 0b00100000, 0b01110000, 0b10101000, 0b00100000, 0b01010000, 0b10001000, //figure2 0b01110000, 0b10101000, 0b01110000, 0b00100000, 0b00100000, 0b01010000, 0b10001000}; //================================ //3x5 font numbers, then letters //packed two per definition for fast //copy to the screen at x-position divisible by 4 flash char smallbitmap[39][5]={ //0 0b11101110, 0b10101010, 0b10101010, 0b10101010, 0b11101110, //1 0b01000100, 0b11001100, 0b01000100, 0b01000100, 0b11101110, //2 0b11101110, 0b00100010, 0b11101110, 0b10001000, 0b11101110, //3 0b11101110, 0b00100010, 0b11101110, 0b00100010, 0b11101110, //4 0b10101010, 0b10101010, 0b11101110, 0b00100010, 0b00100010, //5 0b11101110, 0b10001000, 0b11101110, 0b00100010, 0b11101110, //6 0b11001100, 0b10001000, 0b11101110, 0b10101010, 0b11101110, //7 0b11101110, 0b00100010, 0b01000100, 0b10001000, 0b10001000, //8 0b11101110, 0b10101010, 0b11101110, 0b10101010, 0b11101110, //9 0b11101110, 0b10101010, 0b11101110, 0b00100010, 0b01100110, //: 0b00000000, 0b01000100, 0b00000000, 0b01000100, 0b00000000, //= 0b00000000, 0b11101110, 0b00000000, 0b11101110, 0b00000000, //blank 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, //A 0b11101110, 0b10101010, 0b11101110, 0b10101010, 0b10101010, //B 0b11001100, 0b10101010, 0b11101110, 0b10101010, 0b11001100, //C 0b11101110, 0b10001000, 0b10001000, 0b10001000, 0b11101110, //D 0b11001100, 0b10101010, 0b10101010, 0b10101010, 0b11001100, //E 0b11101110, 0b10001000, 0b11101110, 0b10001000, 0b11101110, //F 0b11101110, 0b10001000, 0b11101110, 0b10001000, 0b10001000, //G 0b11101110, 0b10001000, 0b10001000, 0b10101010, 0b11101110, //H 0b10101010, 0b10101010, 0b11101110, 0b10101010, 0b10101010, //I 0b11101110, 0b01000100, 0b01000100, 0b01000100, 0b11101110, //J 0b00100010, 0b00100010, 0b00100010, 0b10101010, 0b11101110, //K 0b10001000, 0b10101010, 0b11001100, 0b11001100, 0b10101010, //L 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b11101110, //M 0b10101010, 0b11101110, 0b11101110, 0b10101010, 0b10101010, //N 0b00000000, 0b11001100, 0b10101010, 0b10101010, 0b10101010, //O 0b01000100, 0b10101010, 0b10101010, 0b10101010, 0b01000100, //P 0b11101110, 0b10101010, 0b11101110, 0b10001000, 0b10001000, /* //Q 0b01000100, 0b10101010, 0b10101010, 0b11101110, 0b01100110, */ //Q - Represents a space 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, //R 0b11101110, 0b10101010, 0b11001100, 0b11101110, 0b10101010, //S 0b11101110, 0b10001000, 0b11101110, 0b00100010, 0b11101110, //T 0b11101110, 0b01000100, 0b01000100, 0b01000100, 0b01000100, //U 0b10101010, 0b10101010, 0b10101010, 0b10101010, 0b11101110, //V 0b10101010, 0b10101010, 0b10101010, 0b10101010, 0b01000100, //W 0b10101010, 0b10101010, 0b11101110, 0b11101110, 0b10101010, //X 0b00000000, 0b10101010, 0b01000100, 0b01000100, 0b10101010, //Y 0b10101010, 0b10101010, 0b01000100, 0b01000100, 0b01000100, //Z 0b11101110, 0b00100010, 0b01000100, 0b10001000, 0b11101110 }; //================================== //This is the sync generator and raster generator. It MUST be entered from //sleep mode to get accurate timing of the sync pulses #pragma warn- interrupt [TIM1_COMPA] void t1_cmpA(void) begin //increment sound counter if (sound_counter2 < 10000) begin /* //Produce startup screen music if (tone == 4 && sound_counter2 == 2000) begin tone = 9; end else if (tone == 9 && sound_counter2 == 5000) tone = 5; else if (tone == 5 && sound_counter2 == 8000) tone = 7; */ //Produce win tones if (sound_counter2 == 6000) begin tone = 6; end if (sound_counter < tone) begin sound_counter++; end else begin sound_counter = 0; PORTB = ~PORTB; end sound_counter2++; end //start the Horizontal sync pulse PORTD = syncON; //update the curent scanline number LineCount ++ ; //begin inverted (Vertical) synch after line 247 if (LineCount==248) begin syncON = 0b00100000; syncOFF = 0; end //back to regular sync after line 250 if (LineCount==251) begin syncON = 0; syncOFF = 0b00100000; end //start new frame after line 262 if (LineCount==263) begin LineCount = 1; end delay_us(2); //adjust to make 5 us pulses //end sync pulse PORTD = syncOFF; if (LineCount=ScreenTop) begin //compute byte index for beginning of the next line //left-shift 4 would be individual lines // <<3 means line-double the pixels //The 0xfff8 truncates the odd line bit //i=(LineCount-ScreenTop)<<3 & 0xfff8; // #asm push r16 lds r12, _LineCount lds r13, _Linecount+1 ldi r16, 30 sub r12, r16 ldi r16,0 sbc r13, r16 lsl r12 rol r13 lsl r12 rol r13 lsl r12 rol r13 mov r16,r12 andi r16,0xf0 mov r12,r16 pop r16 #endasm //load 16 registers with screen info #asm push r14 push r15 push r16 push r17 push r18 push r19 push r26 push r27 ldi r26,low(_screen) ;base address of screen ldi r27,high(_screen) add r26,r12 ;offset into screen (add i) adc r27,r13 ld r4,x+ ;load 16 registers and inc pointer ld r5,x+ ld r6,x+ ld r7,x+ ld r8,x+ ld r9,x+ ld r10,x+ ld r11,x+ ld r12,x+ ld r13,x+ ld r14,x+ ld r15,x+ ld r16,x+ ld r17,x+ ld r18,x+ ld r19,x pop r27 pop r26 #endasm delay_us(4); //adjust to center image on screen //blast 16 bytes to the screen #asm ;but first a macro to make the code shorter ;the macro takes a register number as a parameter ;and dumps its bits serially to portD.6 ;the nop can be eliminated to make the display narrower .macro videobits ;regnum BST @0,7 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,6 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,5 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,4 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,3 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,2 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,1 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,0 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 .endm videobits r4 ;video line -- byte 1 videobits r5 ;byte 2 videobits r6 ;byte 3 videobits r7 ;byte 4 videobits r8 ;byte 5 videobits r9 ;byte 6 videobits r10 ;byte 7 videobits r11 ;byte 8 videobits r12 ;byte 9 videobits r13 ;byte 10 videobits r14 ;byte 11 videobits r15 ;byte 12 videobits r16 ;byte 13 videobits r17 ;byte 14 videobits r18 ;byte 15 videobits r19 ;byte 16 clt ;clear video after the last pixel on the line IN R30,0x12 BLD R30,6 OUT 0x12,R30 pop r19 pop r18 pop r17 pop r16 pop r15 pop r14 #endasm end end #pragma warn+ //================================== //plot one point //at x,y with color 1=white 0=black 2=invert #pragma warn- void video_pt(char x, char y, char c) begin #asm ; i=(x>>3) + ((int)y<<4) ; the byte with the pixel in it push r16 ldd r30,y+2 ;get x lsr r30 lsr r30 lsr r30 ;divide x by 8 ldd r12,y+1 ;get y lsl r12 ;mult y by 16 clr r13 lsl r12 rol r13 lsl r12 rol r13 lsl r12 rol r13 add r12, r30 ;add in x/8 ;v2 = screen[i]; r5 ;v3 = pos[x & 7]; r6 ;v4 = c r7 ldi r30,low(_screen) ldi r31,high(_screen) add r30, r12 adc r31, r13 ld r5,Z ;get screen byte ldd r26,y+2 ;get x ldi r27,0 andi r26,0x07 ;form x & 7 ldi r30,low(_pos*2) ldi r31,high(_pos*2) add r30,r26 adc r31,r27 lpm r6,Z ld r16,y ;get c ;if (v4==1) screen[i] = v2 | v3 ; ;if (v4==0) screen[i] = v2 & ~v3; ;if (v4==2) screen[i] = v2 ^ v3 ; cpi r16,1 brne tst0 or r5,r6 tst0: cpi r16,0 brne tst2 com r6 and r5,r6 tst2: cpi r16,2 brne writescrn eor r5,r6 writescrn: ldi r30,low(_screen) ldi r31,high(_screen) add r30, r12 adc r31, r13 st Z, r5 ;write the byte back to the screen pop r16 #endasm end #pragma warn+ //================================== // put a big character on the screen // c is index into bitmap void video_putchar(char x, char y, char c) begin v7 = x; for (v6=0;v6<7;v6++) begin v1 = bitmap[c][v6]; v8 = y+v6; video_pt(v7, v8, (v1 & 0x80)==0x80); video_pt(v7+1, v8, (v1 & 0x40)==0x40); video_pt(v7+2, v8, (v1 & 0x20)==0x20); video_pt(v7+3, v8, (v1 & 0x10)==0x10); video_pt(v7+4, v8, (v1 & 0x08)==0x08); end end //================================== // put a string of big characters on the screen void video_puts(char x, char y, char *str) begin char i ; for (i=0; str[i]!=0; i++) begin if (str[i]>=0x30 && str[i]<=0x3a) video_putchar(x,y,str[i]-0x30); else video_putchar(x,y,str[i]-0x40+9); x = x+6; end end //================================== // put a small character on the screen // x-cood must be on divisible by 4 // c is index into bitmap void video_smallchar(char x, char y, char c) begin char mask; i=((int)x>>3) + ((int)y<<4) ; if (x == (x & 0xf8)) mask = 0x0f; //f8 else mask = 0xf0; screen[i] = (screen[i] & mask) | (smallbitmap[c][0] & ~mask); screen[i+16] = (screen[i+16] & mask) | (smallbitmap[c][1] & ~mask); screen[i+32] = (screen[i+32] & mask) | (smallbitmap[c][2] & ~mask); screen[i+48] = (screen[i+48] & mask) | (smallbitmap[c][3] & ~mask); screen[i+64] = (screen[i+64] & mask) | (smallbitmap[c][4] & ~mask); end //================================== // put a string of small characters on the screen // x-cood must be on divisible by 4 void video_putsmalls(char x, char y, char *str) begin char i ; for (i=0; str[i]!=0; i++) begin if (str[i]>=0x30 && str[i]<=0x3a) video_smallchar(x,y,str[i]-0x30); else video_smallchar(x,y,str[i]-0x40+12); x = x+4; end end void video_putbrick(char x, char y, char c) begin v7 = x; for (v6 = 0; v6 < 8; v6++) begin v1 = bricks[c][v6]; v8 = y+v6; video_pt(v7, v8, (v1 & 0x80)==0x80); video_pt(v7+1, v8, (v1 & 0x40)==0x40); video_pt(v7+2, v8, (v1 & 0x20)==0x20); video_pt(v7+3, v8, (v1 & 0x10)==0x10); video_pt(v7+4, v8, (v1 & 0x08)==0x08); video_pt(v7+5, v8, (v1 & 0x04)==0x04); video_pt(v7+6, v8, (v1 & 0x02)==0x02); video_pt(v7+7, v8, (v1 & 0x01)==0x01); end end void video_putpower(char x, char y, char c) begin v7 = x; for (v6 = 0; v6 < 8; v6++) begin v1 = power[c][v6]; v8 = y+v6; video_pt(v7, v8, (v1 & 0x80)==0x80); video_pt(v7+1, v8, (v1 & 0x40)==0x40); video_pt(v7+2, v8, (v1 & 0x20)==0x20); video_pt(v7+3, v8, (v1 & 0x10)==0x10); video_pt(v7+4, v8, (v1 & 0x08)==0x08); video_pt(v7+5, v8, (v1 & 0x04)==0x04); video_pt(v7+6, v8, (v1 & 0x02)==0x02); video_pt(v7+7, v8, (v1 & 0x01)==0x01); end end //================================== //plot a line //at x1,y1 to x2,y2 with color 1=white 0=black 2=invert //NOTE: this function requires signed chars //Code is from David Rodgers, //"Procedural Elements of Computer Graphics",1985 void video_line(char x1, char y1, char x2, char y2, char c) begin int e; signed char dx,dy,j, temp; signed char s1,s2, xchange; signed char x,y; x = x1; y = y1; dx = cabs(x2-x1); dy = cabs(y2-y1); s1 = csign(x2-x1); s2 = csign(y2-y1); xchange = 0; if (dy>dx) begin temp = dx; dx = dy; dy = temp; xchange = 1; end e = ((int)dy<<1) - dx; for (j=0; j<=dx; j++) begin video_pt(x,y,c) ; if (e>=0) begin if (xchange==1) x = x + s1; else y = y + s2; e = e - ((int)dx<<1); end if (xchange==1) y = y + s2; else x = x + s1; e = e + ((int)dy<<1); end end //================================== //return the value of one point //at x,y with color 1=white 0=black 2=invert char video_set(char x, char y) begin //The following construction //detects exactly one bit at the x,y location i=((int)x>>3) + ((int)y<<4) ; return ( screen[i] & 1<<(7-(x & 0x7))); end //================================== // set up the ports and timers void main(void) begin char h, brick_count, clear, b2_activate, b1_activate, randx, randy, tempx, tempy, player_num = 1, hit_ind, hit_ind2, life2, b1_count, b2_count; unsigned long points = 0; int a = 0, b; //init timer 1 to generate sync OCR1A = lineTime; //One NTSC line TCCR1B = 9; //full speed; clear-on-match TCCR1A = 0x00; //turn off pwm and oc lines TIMSK = 0x10; //enable interrupt T1 cmp //init port D DDRD = 0xF0; //video out and switches //D.5 is sync:1000 ohm + diode to 75 ohm resistor //D.6 is video:330 ohm + diode to 75 ohm resistor //initialize synch constants LineCount = 1; syncON = 0b00000000; syncOFF = 0b00100000; //initialize sound counter and initially set PORTB to input sound_counter = 0; DDRB = 0xFF; PORTB = 0x00; sound_counter2 = 10000; tone = 6; /**************init the A to D converter***************/ //init the A to D converter //channel zero/ left adj /EXTERNAL Aref //!!!CONNECT Aref jumper!!!! ADMUX = 0b00100000; //enable ADC and set prescaler to 1/128*16MHz=125,000 //and clear interupt enable //and start a conversion ADCSR = 0b11000111; /******************************************************/ h = -1; //Initially enters Welcome screen #define width 126 //Defines width of screen to be 126 pixels while(h < 10) begin if(h == -1) begin /****************************** WELCOME SCREEN ******************************/ for(a = 0; a < 1600; a++) screen[a] = 0; //Erase screen //DRAW BORDERS AROUND SIDES OF SCREEN //side lines video_line(0,0,0,99,1); video_line(width,0,width,99,1); //top line & bottom lines video_line(0,0,width,0,1); video_line(0,99,width,99,1); video_line(0,11,width,11,1); video_line(0,89,width,89,1); #asm("sei"); //Enable interrupts for welcome screen for(a = 0; a < 500; a++) begin for(b = 0; b < 100; b++) begin if(LineCount == 231) begin sprintf(ts,"SUPER"); video_puts(20,25,ts); sprintf(ts,"BREAKOUT"); video_puts(60,25,ts); /* if (a == 50) begin sound_counter2 = 0; tone = 4; end*/ end end end for(a = 0; a < 4500; a++) begin if((a%2) == 0) begin ADMUX = 0b00100001; avalue = ADCH; end else begin ADMUX = 0b00100000; temp = ADCH; end ADCSR.6 = 1; for(b = 0; b < 100; b++) begin //store variables to detect change in modes //temp_mode = mode; // temp_player = player_num; if(LineCount == 231) begin sprintf(ts,"PLAYERS:"); video_putsmalls(24,40,ts); if(avalue <= 0) begin sprintf(ts,"1"); player_num = 1; video_putsmalls(60,40,ts); //Erases "MODE:" and "COOPERATIVE" sprintf(ts,"QQQQQQ"); video_putsmalls(24,50,ts); sprintf(ts,"QQQQQQQQQQQ"); video_putsmalls(60,50,ts); mode = 0; end else begin sprintf(ts,"2"); player_num = 2; video_putsmalls(60,40,ts); sprintf(ts,"MODE:Q"); video_putsmalls(24,50,ts); if((temp > 0)&&(temp < 75)) begin sprintf(ts,"COMPETITIVE"); mode = 1; end else if(temp >= 75) begin sprintf(ts, "COOPERATIVE"); mode = 0; end else begin sprintf(ts, "KNOCKOUTQQQ"); mode = 2; end video_putsmalls(60,50,ts); end end end /* //If mode change is detected, play a sound if (temp_mode != mode) begin sound_counter2 = 8000; //Produce a sound for mode switch tone = 6; temp_mode = mode; end else if (temp_player != player_num) begin sound_counter2 = 8000; //Produce a sound for mode switch tone = 6; temp_player = player_num; end*/ end #asm("cli"); //disable interrupts before calculating brick positions //Erases erraneous text from startup screen (mode: blah) sprintf(ts,"QQQQQQ"); video_putsmalls(24,50,ts); sprintf(ts,"QQQQQQQQQQQ"); video_putsmalls(60,50,ts); h = 0; //Set h to not enter welcome screen again if(mode == 1) //Competitive Play Mode begin p2y = 16; //Player 2's y paddle position p1y = 0x55; player_num = 2; life = 3; //Player 1 & 2 start with 3 lives life2 = 3; b2_activate = 1; //Activate Ball 2 initially x2pos = 0x1500; //x = 21 y2pos = 0x2800; //y = 40 v2x = 0x0080; v2y = 0x0080; //Initially going up end else if(mode == 0) //Non-Competitive play begin b2_activate = 0; //Inactivate Ball 2 initially p2y = 0x53; p1y = 0x55; life = 9; //Give player(s) 9 lives (single digit) life2 = 0; end else if(mode == 2) begin for(a = 0; a < 1600; a++) screen[a] = 0; //DRAW BORDERS AROUND SIDES OF SCREEN //side lines video_line(0,0,0,99,1); video_line(width,0,width,99,1); //top line & bottom lines video_line(0,0,width,0,1); video_line(0,99,width,99,1); video_line(0,11,width,11,1); video_line(0,89,width,89,1); for(a = 0; a < 2; a++) begin for(b = 0; b < 15; b++) begin protect_brick[a][b] = 1; if(a == 0) video_putbrick((b<<3)+4,(a<<3)+13, 1); else video_putbrick((b<<3)+4,(a<<3)+72, 1); end end b1_count = 15; b2_count = 15; p2y = 0x18; p1y = 0x4C; player_num = 2; b2_activate = 1; //Activate Ball 2 initially x2pos = 0x1500; //x = 21 y2pos = 0x2800; //y = 40 v2x = 0x0080; v2y = 0x0080; //Initially going up end end if(mode != 2) begin sprintf(ts,"LIVESQ%d",life); video_putsmalls(4,5,ts); sprintf(ts,"LEVELQ%d",h+1); end else sprintf(ts,"KNOCKOUT"); video_puts(42,3,ts); //init software timer t = 0; time = 0; //initialize Player 1 p1_posx = 0x0A00; //x = 60 //initialize Player 2 p2_posx = 0x4600; //initialize Ball 1 (activate) b1_activate = 1; //Activate Ball 1 initially x1pos = 0x1500; //x = 21 y1pos = 0x3C00; //y = 60 v1x = 0x0080; v1y = -(0x0080); //Initially going up //initialize Ball 2 (inactivate) brick_count = 0; //0 bricks clear = 0; //Level not cleared p1_width = 0x12; //paddle 1's width p2_width = 0x12; //paddle 2's width hit_ind = 0; //Initialize 'hit indestructible' flag to 0 hit_ind2 = 0; power_pos[0][0] = 0; power_pos[0][1] = 0; power_pos[0][2] = 0; srand(ADCH >> 3); //randomize C's random # generator using the accelerometer reading ADCSR.6 = 1; if(mode == 0) //Non-Competitive Play mode -> 10 Custom levels begin /**********************CREATE LEVELS (for Mode 0)*****************/ //Level 1 - 1 paddle lengthener if(h == 0) begin for(a = 0; a < 4; a++) begin for(b = 0; b < 15; b++) begin if((a == 1)||(a == 3)) temp = 0; else temp = 1; brick_pos[a][b] = temp; video_putbrick((b<<3)+4,(a<<3)+17, temp); if(temp != 0) brick_count++; end end //Power-up: randx = rand()&0x07; while((randx >= 4)||(randx == 1)||(randx == 3)) randx = rand()&0x07; randy = rand()&0x0F; while(randy >= 15) randy = rand()&0x0F; brick_pos[randx][randy] = 3; video_putbrick((randy<<3)+4,(randx<<3)+17, 3); end //Level 2 else if(h == 1) begin for(a = 0; a < 4; a++) begin for(b = 0; b < 15; b++) begin if((b == 2) || (b == 12)) temp = 5; else temp = 1; brick_pos[a][b] = temp; video_putbrick((b<<3)+4,(a<<3)+17, temp); //Does not count indestructible and blanks if((temp != 0)&&(temp != 5)) brick_count++; end end //Paddle lengthener randx = rand()&0x07; while(randx >= 4) randx = rand()&0x07; randy = rand()&0x0F; while((randy >= 15)||(randy == 2)||(randy == 12)) randy = rand()&0x0F; brick_pos[randx][randy] = 3; video_putbrick((randy<<3)+4,(randx<<3)+17, 3); //Draw one second ball brick randx = rand()&0x07; while(randx >= 4) randx = rand()&0x07; randy = rand()&0x0F; while((randy >= 15)||(randy == 2)||(randy == 12)) randy = rand()&0x0F; brick_pos[randx][randy] = 2; video_putbrick((randy<<3)+4,(randx<<3)+17, 2); end //Level 3 else if(h == 2) begin for(a = 0; a < 4; a++) begin for(b = 0; b < 15; b++) begin if((a == 2)&&(b > 3)&&(b < 11)) temp = 5; else temp = 1; brick_pos[a][b] = temp; video_putbrick((b<<3)+4,(a<<3)+17, temp); //Does not count indestructible and blanks if((temp != 0)&&(temp != 5)) brick_count++; end end //Paddle Lengthener randx = rand()&0x07; while((randx >= 4)||(randx == 2)) randx = rand()&0x07; randy = rand()&0x0F; while(randy >= 15) randy = rand()&0x0F; brick_pos[randx][randy] = 3; video_putbrick((randy<<3)+4,(randx<<3)+17, 3); //Draw one second ball brick randx = rand()&0x07; while((randx >= 4)||(randx == 2)) randx = rand()&0x07; randy = rand()&0x0F; while(randy >= 15) randy = rand()&0x0F; brick_pos[randx][randy] = 2; video_putbrick((randy<<3)+4,(randx<<3)+17, 2); end //Level 4 else if(h == 3) begin for(a = 0; a < 4; a++) begin for(b = 0; b < 15; b++) begin if(a < 3) begin if((b % 2) == 1) temp = 1; else temp = 0; end else begin if((b >= 1) && (b <= 13)) temp = 5; else temp = 0; end brick_pos[a][b] = temp; video_putbrick((b<<3)+4,(a<<3)+17, temp); //Does not count indestructible and blanks if((temp != 0)&&(temp != 5)) brick_count++; end end //Paddle lengthener randx = rand()&0x07; while((randx >= 4)||(randx == 3)) randx = rand()&0x07; randy = rand()&0x0F; while((randy >= 15)||((randy%2) == 0)) randy = rand()&0x0F; brick_pos[randx][randy] = 3; video_putbrick((randy<<3)+4,(randx<<3)+17, 3); //Draw one second ball brick randx = rand()&0x07; while((randx >= 4)||(randx == 3)) randx = rand()&0x07; randy = rand()&0x0F; while((randy >= 15)||((randy%2) == 0)) randy = rand()&0x0F; brick_pos[randx][randy] = 2; video_putbrick((randy<<3)+4,(randx<<3)+17, 2); end //Level 5 else if(h == 4) begin for(a = 0; a < 4; a++) begin for(b = 0; b < 15; b++) begin if(a == 0) temp = 5; else if((a == 1) || (a == 2)) begin if((b == 0) || (b == 14)) temp = 5; else temp = 1; end else begin if((b <=4) || (b >= 10)) temp = 5; else temp = 1; end brick_pos[a][b] = temp; video_putbrick((b<<3)+4,(a<<3)+17, temp); //Does not count indestructible and blanks if((temp != 0)&&(temp != 5)) brick_count++; end end //Paddle lengthener randx = rand()&0x07; while((randx >= 4)||(randx == 0)||(randx == 3)) randx = rand()&0x07; randy = rand()&0x0F; while((randy >= 15)||(randy == 0)||(randy == 14)) randy = rand()&0x0F; brick_pos[randx][randy] = 3; video_putbrick((randy<<3)+4,(randx<<3)+17, 3); //Draw one second ball brick randx = rand()&0x07; while((randx >= 4)||(randx == 0)||(randx == 3)) randx = rand()&0x07; randy = rand()&0x0F; while((randy >= 15)||(randy == 0)||(randy == 14)) randy = rand()&0x0F; brick_pos[randx][randy] = 2; video_putbrick((randy<<3)+4,(randx<<3)+17, 2); end //Level 6 else if(h == 5) begin for(a = 0; a < 4; a++) begin for(b = 0; b < 15; b++) begin if(b == 7) temp = 0; else if((b != 7)&&((a == 0) || (a == 2))) temp = 5; else temp = 1; brick_pos[a][b] = temp; video_putbrick((b<<3)+4,(a<<3)+17, temp); //Does not count indestructible and blanks if((temp != 0)&&(temp != 5)) brick_count++; end end //Point Doubler randx = rand()&0x07; while((randx >= 4)||(randx == 0)||(randx == 2)) randx = rand()&0x07; randy = rand()&0x0F; while((randy >= 15)||(randy == 7)) randy = rand()&0x0F; brick_pos[randx][randy] = 4; video_putbrick((randy<<3)+4,(randx<<3)+17, 4); //Draw one second ball brick randx = rand()&0x07; while((randx >= 4)||(randx == 0)||(randx == 2)) randx = rand()&0x07; randy = rand()&0x0F; while((randy >= 15)||(randy == 7)) randy = rand()&0x0F; brick_pos[randx][randy] = 2; video_putbrick((randy<<3)+4,(randx<<3)+17, 2); end //Level 7 else if(h == 6) begin for(a = 0; a < 4; a++) begin for(b = 0; b < 15; b++) begin if(a == 0) begin if(b <= 2) temp = 5; else temp = 1; end else if(a == 1) begin if((b >= 3) && (b <= 6)) temp = 5; else temp = 1; end else if(a == 2) begin if((b >= 7) && (b <= 10)) temp = 5; else temp = 1; end else begin if((b >= 11) && (b <= 14)) temp = 5; else temp = 1; end brick_pos[a][b] = temp; video_putbrick((b<<3)+4,(a<<3)+17, temp); //Does not count indestructible and blanks if((temp != 0)&&(temp != 5)) brick_count++; end end //Paddle Lengthener randx = rand()&0x07; while(randx >= 4) randx = rand()&0x07; randy = rand()&0x0F; if(randx < 2) begin while((randy >= 15) || (randy < 7)) randy = rand()&0x0F; end else begin while(randy > 7) randy = rand()&0x0F; end brick_pos[randx][randy] = 3; video_putbrick((randy<<3)+4,(randx<<3)+17, 3); //Draw one second ball brick randx = rand()&0x07; while(randx >= 4) randx = rand()&0x07; randy = rand()&0x0F; if(randx < 2) begin while((randy >= 15) || (randy < 7)) randy = rand()&0x0F; end else begin while(randy > 7) randy = rand()&0x0F; end brick_pos[randx][randy] = 2; video_putbrick((randy<<3)+4,(randx<<3)+17, 2); end //Level 8 else if(h == 7) begin for(a = 0; a < 4; a++) begin for(b = 0; b < 15; b++) begin if((a == 0) || (a == 3)) begin if((b < 3) || (b > 11)) temp = 5; else temp = 1; end else begin if((b >= 4) && (b <= 10)) temp = 5; else temp = 1; end brick_pos[a][b] = temp; video_putbrick((b<<3)+4,(a<<3)+17, temp); //Does not count indestructible and blanks if((temp != 0)&&(temp != 5)) brick_count++; end end //Point Doubler randx = rand()&0x07; while((randx >= 4)||(randx == 0)||(randx == 3)) randx = rand()&0x07; randy = rand()&0x0F; while((randy >= 15)||((randy > 3)&&(randy < 11))) randy = rand()&0x0F; brick_pos[randx][randy] = 4; video_putbrick((randy<<3)+4,(randx<<3)+17, 4); //Draw one second ball brick randx = rand()&0x07; while((randx >= 4)||(randx == 0)||(randx == 3)) randx = rand()&0x07; randy = rand()&0x0F; while((randy >= 15)||((randy > 3)&&(randy < 11))) randy = rand()&0x0F; brick_pos[randx][randy] = 2; video_putbrick((randy<<3)+4,(randx<<3)+17, 2); end //Level 9 else if(h == 8) begin for(a = 0; a < 4; a++) begin for(b = 0; b < 15; b++) begin if((a == 0) || (a == 2)) begin if((b == 1) || (b == 4) || (b == 7) || (b == 10) || (b == 13)) temp = 5; else temp = 1; end else if(a == 1) begin if((b == 0) || (b == 3) || (b == 6) || (b == 9) || (b == 12)) temp = 5; else temp = 1; end else begin if((b == 2) || (b == 5) || (b == 8) || (b == 11) || (b == 14)) temp = 5; else temp = 1; end brick_pos[a][b] = temp; video_putbrick((b<<3)+4,(a<<3)+17, temp); //Does not count indestructible and blanks if((temp != 0)&&(temp != 5)) brick_count++; end end temp = rand()&0x06; while(temp == 0) temp = rand()&0x06; brick_pos[0][0] = temp; video_putbrick(4,17, temp); temp = rand()&0x06; while(temp == 0) temp = rand()&0x06; brick_pos[0][14] = temp; video_putbrick(116,+17, temp); temp = rand()&0x06; brick_pos[3][0] = temp; while(temp == 0) temp = rand()&0x06; video_putbrick(4,41, temp); temp = rand()&0x06; while(temp == 0) temp = rand()&0x06; brick_pos[1][7] = rand()&0x06; video_putbrick(60,25, temp); end //Level 10 else if(h == 9) begin //Draw matrix of bricks for(a = 0; a < 4; a++) begin for(b = 0; b < 15; b++) begin if((a == 0) || (a == 2)) begin if((b%2) == 0) temp = 5; else temp = 1; end else begin if((b % 2) == 1) temp = 5; else temp = 1; end brick_pos[a][b] = temp; video_putbrick((b<<3)+4,(a<<3)+17, temp); //Does not count indestructible and blanks if((temp != 0)&&(temp != 5)) brick_count++; end end temp = rand()&0x06; while(temp == 0) temp = rand()&0x06; brick_pos[0][0] = temp; video_putbrick(4,17, temp); temp = rand()&0x06; while(temp == 0) temp = rand()&0x06; brick_pos[3][0] = rand()&0x06; video_putbrick(4,41, temp); temp = rand()&0x06; while(temp == 0) temp = rand()&0x06; brick_pos[0][14] = rand()&0x06; video_putbrick(116,17, temp); end end else if(mode == 1) //mode = 1 (COMPETITIVE MODE) begin brick_count = 0; for(a = 0; a < 4; a++) begin for(b = 0; b < 15; b++) begin if (a == 3) begin temp = rand()&0x05; while(temp == 4) temp = rand()&0x05; if((temp != 5)&&(temp != 0)) brick_count++; end else temp = 0; brick_pos[a][b] = temp; video_putbrick((b<<3)+4,(a<<3)+17, temp); end end end //enable sleep mode MCUCR = 0b10000000; #asm ("sei"); /*****************TESTING USE ONLY********************/ brick_count = 5; /*****************************************************/ //The following loop executes once/video line during lines //1-230, then does all of the frame-end processing while(!clear) begin //stall here until next line starts //sleep enable; mode=idle //use sleep to make entry into sync ISR uniform time #asm ("sleep"); //The following code executes during the vertical blanking //Code here can be as long as //a total of 60 lines x 63.5 uSec/line x 8 cycles/uSec if((LineCount == 231)&&(!clear)) //Skip if game is over begin //Swap between sampling Player 1 and Player 2's accelerometer if((ADMUX & 0x01) == 0x01) begin p2x_move = ADCH; //Sample Player2's accelerometer ADMUX = 0b00100000; //Allow ADC of Player1's accelerometer end else begin p1x_move = ADCH; //Sample Player1's accelerometer ADMUX = 0b00100001; //Allow ADC of Player2's accelerometer end ADCSR.6=1; /***********************PADDLE 1 UPDATE*****************************/ //'paddle' is of type int because of overflow in a char //'paddle' is used to calculate length of paddle in int //'temp' is the char value. If overflows, set to max width of 124 to ensure a ball hits paddle //Erase paddle 1 paddle = (int)((int)p1x + (int)p1_width); temp = (char)paddle; if(paddle <= 0x007C) //paddle does not extend past screen begin video_line(p1x,p1y-1, temp,p1y-1,0); video_line(p1x,p1y, temp,p1y,0); end else //paddle extends beyond screen, only erase to limits of screen begin video_line(p1x,p1y-1, 124,p1y-1,0); video_line(p1x,p1y, 124,p1y,0); end //Update paddle 1 position based on accelerometer (gradual change) if((p1x_move > 0)&&(p1_posx <= (int)(0x007C-(int)p1_width)<<8)) //Move to right begin temp = 128 - p1x_move; if(temp < 5) p1_posx += 0x0010; else if(temp < 10) p1_posx += 0x0020; else if(temp < 15) p1_posx += 0x0040; else if(temp < 20) p1_posx += 0x0080; else p1_posx += 0x0100; end else if(p1_posx >= 0x0200) begin temp = 128 + p1x_move; if(temp < 5) p1_posx -= 0x0010; else if(temp < 10) p1_posx -= 0x0020; else if(temp < 15) p1_posx -= 0x0040; else if(temp < 20) p1_posx -= 0x0080; else p1_posx -= 0x0100; end //Draw paddle 1 paddle = (int)((int)p1x + (int)p1_width); temp = (char)paddle; if(paddle <= 0x007C) //paddle does not extend past screen begin video_line(p1x,p1y-1, temp,p1y-1,1); video_line(p1x,p1y, temp,p1y,1); end else //Paddle extends beyond screen, only draw to limits of screen begin video_line(p1x,p1y-1, 124,p1y-1,1); video_line(p1x,p1y, 124,p1y,1); end /*******************************************************************/ /***********************PADDLE 2 UPDATE*****************************/ if(player_num == 2) begin //Erase paddle 2 paddle = (int)((int)p2x + (int)p2_width); temp = (char)paddle; if(paddle <= 0x007C) begin video_line(p2x,p2y-1, temp,p2y-1,0); video_line(p2x,p2y, temp,p2y,0); end else begin video_line(p2x,p2y-1, 124,p2y-1,0); video_line(p2x,p2y, 124,p2y,0); end //Update paddle 2 movements if((p2x_move > 0)&&(p2_posx <= (int)(0x007C-(int)p2_width)<<8)) //Move to right begin temp = 128 - p2x_move; if(temp < 5) p2_posx += 0x0010; else if(temp < 10) p2_posx += 0x0020; else if(temp < 15) p2_posx += 0x0040; else if(temp < 20) p2_posx += 0x0080; else p2_posx += 0x0100; end else if(p2_posx >= 0x0200) begin temp = 128 + p2x_move; if(temp < 5) p2_posx -= 0x0010; else if(temp < 10) p2_posx -= 0x0020; else if(temp < 15) p2_posx -= 0x0040; else if(temp < 20) p2_posx -= 0x0080; else p2_posx -= 0x0100; end //Draw paddle 2 paddle = (int)((int)p2x + (int)p2_width); temp = (char)paddle; if(paddle <= 0x007C) begin video_line(p2x,p2y-1, temp,p2y-1,1); video_line(p2x,p2y, temp,p2y,1); end else //Do not draw paddle 2 off-screen begin video_line(p2x,p2y-1, 124,p2y-1,1); video_line(p2x,p2y, 124,p2y,1); end end /*******************************************************************/ if((mode == 0) || (mode == 1)) begin //Ball 1 is active if(b1_activate) begin //Hit an indestructible brick, do not erase previous ball if(!hit_ind) video_pt(x1,y1,0); //erase old ball 1 else hit_ind = 0; x1pos += v1x; y1pos += v1y; //if PLAYER 1 paddle is hit, change y velocity appropriately if((y1 == p1y-1)||(y1 == p1y)||(y1 == p1y+1)||(y1 == p1y+2)) begin //paddle is of type int because of overflow in a char //paddle is used to calculate length of paddle in int //temp is the char value. If overflows, set to max width of 124 to ensure a ball hits paddle paddle = (int)((int)p1x+(int)p1_width); if(paddle <= 124) temp = (char)paddle; else temp = 124; if((x1 >= p1x)&&(x1 <= temp)&&(y1 > 80)) //Ball is within width of paddle 1 begin v1x += (x1pos - (p1_posx+(((int)p1_width<<8)>>1)))>>4; v1y = -v1y; //change y velocity sound_counter2 = 9200; //Produce a sound tone = 6; end end //if PLAYER 2 paddle is hit, change y velocity appropriately else if((player_num == 2)&&((y1 == p2y-1)||(y1 == p2y)||(y1 == p2y+1) || (y1 == (p2y+2-(mode<<2))))) begin paddle = (int)((int)p2x+(int)p2_width); if(paddle <= 124) temp = (char)paddle; else temp = 124; if((x1 >= p2x)&&(x1 <= temp)) begin if(((mode == 1)&&(y1 < 20))||((mode == 0)&&(y1 > 80))) begin v1x += (x1pos - (p2_posx+(((int)p2_width<<8)>>1)))>>4; v1y = -v1y; //change y velocity sound_counter2 = 9200; //Produce a sound tone = 6; end end //if((x1 >= p2x)&&(x1 <= temp)) end //else if((player_num == 2)&&((y1 ==... //Implement a terminal velocity for the ball @ -> 1 pixel/frame if (abs(v1x) >=0x0100) begin if(v1x > 0) v1x = 0x0100; else v1x = -0x0100; end //Hit boundaries check if((x1 >= 124)||(x1 <= 1)) v1x = -v1x; if(y1 <= 12) begin if((mode == 1)&&(life2 != 0)) life2--; v1y = -v1y; end //If the Ball_1 hits the bottom, it is inactivated - Player(s) (or just player 1) loses a life if(y1 >= 88) begin v1y = -v1y; if(mode == 0) begin b1_activate = 0; video_pt(x1,y1, 0); //erase old ball after hitting bottom end if((life != 0)&&(b2_activate == 0)&&(mode == 0)) life--; //Cooperative, only lose life if both blass deactivated else if((mode == 1)&&(life != 0)) life--; //Competitive, player 1 loses life end //Determine if ball is within brick matrix on screen, only check if it is within this region, otherwise pointless if((x1 >= 4)&&(x1 <= 124)&&(y1 <= 49)&&(y1 >= 17)) begin temp = brick_pos[(y1-17)>>3][(x1-4)>>3]; if(video_set(x1,y1)&&(temp > 0)) begin //hit brick on side algorithm: Only change x-velocity tempx = (((x1-4)>>3)<<3)+4; //Top left x-position of 8x8 brick (+1 to compensate for whitespace) tempy = (((y1-17)>>3)<<3)+17+2; //Top y-position of brick (+2 to compensate for whitespace) if((x1 == (tempx+1)) || (x1 == (tempx + 7))) v1x = -v1x; else v1y = -v1y; sound_counter2 = 9200; //Produce a sound tone = 6; switch(temp) begin case 0: case 1: break; case 2: if(!b2_activate) begin //second ball x2pos = x1pos; y2pos = y1pos; v2x = 0x0060; v2y = 0x0060; b2_activate = 1; end break; case 3: //Increase Paddle Length if(!power_pos[0][0]) //brick type 3 -> extend paddle begin power_pos[0][0] = 1; power_pos[1][0] = (int)(tempx)<<8; power_pos[2][0] = (int)(tempy)<<8; end break; case 4: //Point doubler if(!power_pos[0][1]) //brick type 4 -> point doubler begin power_pos[0][1] = 1; power_pos[1][1] = (int)(tempx)<<8; power_pos[2][1] = (int)(tempy)<<8; end break; case 5: break; //Indestructible case 6: //+1 Life if(!power_pos[0][1]) //brick type 6 -> +1 Life begin power_pos[0][2] = 1; power_pos[1][2] = (int)(tempx)<<8; power_pos[2][2] = (int)(tempy)<<8; end break; default: break; end //Increase score based on type of brick hit by ball 1 if(temp != 5) points += (brick_pos[(y1-17)>>3][(x1-4)>>3])<<1; //Erase Brick - if not indestructible type if(temp != 5) begin brick_pos[(y1-17)>>3][(x1-4)>>3] = 0; //Remove in matrix video_putbrick(tempx, tempy - 2, 0); //Remove on screen brick_count--; //update counter hit_ind = 0; end else begin hit_ind = 1; video_putbrick(tempx, tempy - 2, 5); end end //if(video_set(x1,y1)&&(s > 0)) end //((x1 >= 5)&&(x1 <= 123)&&(y1 <= 48)&&(y1 >= 17)) if(!hit_ind) video_pt(x1,y1,1); //draw ball with new position, if didn't hit indestructible end //end if(b1_activate) if(b2_activate) begin if(!hit_ind2) video_pt(x2,y2,0); //erase old ball 1 else hit_ind2 = 0; //Hit an indestructible brick, do not erase previous ball x2pos += v2x; y2pos += v2y; //if paddle is hit, change x velocity appropriately if((y2 == p1y-1)||(y2 == p1y)||(y2 == p1y+1)||(y2 == p1y+2)) begin paddle = (int)((int)p1x+(int)p1_width); if(paddle <= 124) temp = (char)paddle; else temp = 124; if((x2 >= p1x)&&(x2 <= temp)&&(y2 > 80)) begin v2x += (x2pos - (p1_posx+(((int)p1_width<<8)>>1)))>>4; v2y = -v2y; //change y velocity sound_counter2 = 9200; //Produce a sound tone = 6; end end else if((player_num == 2)&&((y2 == p2y-1)||(y2 == p2y)||(y2 == p2y+1)||(y2 == (p2y+2-(mode<<2))))) begin paddle = (int)((int)p2x+(int)p2_width); if(paddle <= 124) temp = (char)paddle; else temp = 124; if((x2 >= p2x) && (x2 <= temp)) begin if(((mode == 1)&&(y2 < 20))||((mode == 0)&&(y2 > 80))) begin v2x += (x2pos - (p2_posx+(((int)p2_width<<8)>>1)))>>4; v2y = -v2y; //change y velocity sound_counter2 = 9200; //Produce a sound tone = 6; end end end if (abs(v2x) >=0x0100) begin if(v2x > 0) v2x = 0x0100; else v2x = -0x0100; end if((x2 >= 124)||(x2 <= 1)) v2x = -v2x; if(y2 <= 12) //Ball hits top, in competitive play, bounces and subtracts life off player 2 begin if((mode == 1)&&(life2 != 0)) life2--; v2y = -v2y; end //If the ball hits the bottom, it is inactivated (Player 1 loses life) if(y2 >= 88) begin v2y = -v2y; if(mode == 0) begin video_pt(x2,y2, 0); b2_activate = 0; end if((life != 0)&&(!b1_activate)&&(mode == 0)) life--; else if((mode == 1)&&(life != 0)) life--; end //Determine if a brick is hit by the second ball and erase the brick when appropriate if((x2 >= 4)&&(x2 <= 124)&&(y2 <= 49)&&(y2 >= 17)) begin temp = brick_pos[(y2-17)>>3][(x2-4)>>3]; if(video_set(x2,y2)&&(temp > 0)) begin tempx = ((((x2-4)>>3)<<3)+4); tempy = (((y2-17)>>3)<<3)+17+2; //top y position of brick (actual brick, no white space) if((x2 == (tempx+1)) || (x2 == (tempx + 7))) v2x = -v2x; else v2y = -v2y; sound_counter2 = 9200; //Produce a sound tone = 6; switch(temp) begin case 0: case 1: break; case 2: if(!b2_activate) begin //second ball x2pos = x1pos; y2pos = y1pos; v2x = 0x0060; v2y = 0x0060; b2_activate = 1; end break; case 3: //Increase Paddle Length if(!power_pos[0][0]) //brick type 3 -> extend paddle begin power_pos[0][0] = 1; power_pos[1][0] = (int)(tempx)<<8; power_pos[2][0] = (int)(tempy)<<8; end break; case 4: //Point doubler if(!power_pos[0][1]) //brick type 4 -> point doubler begin power_pos[0][1] = 1; power_pos[1][1] = (int)(tempx)<<8; power_pos[2][1] = (int)(tempy)<<8; end break; case 5: break; //Indestructible case 6: //+1 Life if(!power_pos[0][1]) //brick type 6 -> +1 Life begin power_pos[0][2] = 1; power_pos[1][2] = (int)(tempx)<<8; power_pos[2][2] = (int)(tempy)<<8; end break; default: break; end //Increase score based on type of brick hit by ball 1 if(temp != 5) points += (brick_pos[(y2-17)>>3][(x2-4)>>3])<<1; //Erase brick - if not indestructible if(temp != 5) begin video_putbrick(tempx, tempy - 2, 0); brick_pos[(y2-17)>>3][(x2-4)>>3] = 0; brick_count--; hit_ind2 = 0; end else begin video_putbrick(tempx, tempy - 2, 5); hit_ind2 = 1; end end end if(!hit_ind2) video_pt(x2,y2,1); //draw ball with new position end //end if(b2_activate) if((brick_count == 0)||((!b1_activate)&&(!b2_activate))) clear = 1; if(power_pos[0][0]) //Paddle Lengthener begin tempx = (char)(power_pos[1][0]>>8); //y-coordinate of power up tempy = (char)((power_pos[2][0]>>8)+6); //x-coordinate of power up //Algorith will replace a brick if the power-up draws over it if((tempx >= 5)&&(tempx <= 123)&&((tempy-6) <= 48)&&((tempy-6) >= 17)) //check only if necessary begin temp = brick_pos[((tempy-6)-17)>>3][(tempx-4)>>3]; if(temp != 0) video_putbrick(((((tempx-4)>>3)<<3)+4), (((((tempy-6)-17)>>3)<<3)+17), temp); end //Paddle Lengthener Power-up has reached the paddle height if(tempy == p1y) begin //power up is in between paddle width if(((tempx+8) >= p1x) && (tempx <= (p1x+p1_width))) begin //increase length of paddle if(p1_width < 0x1E) p1_width += 0x0C; points += 10; //power up is worth 1000 end if((player_num == 2)&&((tempx+8) >= p2x)&&(tempx <= (p2x+p2_width))) begin if(p2_width < 0x1E) p2_width += 0x0C; points += 10; //power up is worth 1000 end video_putbrick(tempx,tempy-6, 0); //blank 8x8 power_pos[0][0] = 0; power_pos[1][0] = 0; power_pos[2][0] = 0; end else //Has not reached bottom, re-draw powerup and erase old one begin video_putpower(tempx, tempy-6, 0); power_pos[2][0] += 0x0040; end //Erase power-up after clearing level if(clear) begin video_putbrick(tempx,tempy-6, 0); //blank 8x8 power_pos[0][0] = 0; power_pos[1][0] = 0; power_pos[2][0] = 0; end end if(power_pos[0][1]) //2X begin tempx = (char)(power_pos[1][1]>>8); //y-coordinate of power up tempy = (char)((power_pos[2][1]>>8)+6); //x-coordinate of power up //Algorithm will replace a brick if the power-up draws over it if((tempx >= 5)&&(tempx <= 123)&&((tempy-6) <= 48)&&((tempy-6) >= 17)) //check only if necessary begin temp = brick_pos[((tempy-6)-17)>>3][(tempx-4)>>3]; if(temp != 0) video_putbrick(((((tempx-4)>>3)<<3)+4), (((((tempy-6)-17)>>3)<<3)+17), temp); end //2x Power-up has reached the paddle height if(tempy == p1y) begin //power up is in between paddle width if(((tempx+8) >= p1x) && (tempx <= (p1x+p1_width))) begin points = points<<1; //double points end if((player_num == 2)&&((tempx+8) >= p2x)&&(tempx <= (p2x+p2_width))) begin points = points<<1; //double points end video_putbrick(tempx,tempy-6, 0); //blank 8x8 power_pos[0][1] = 0; power_pos[1][1] = 0; power_pos[2][1] = 0; end else //Has not reached bottom, re-draw powerup and erase old one begin video_putpower(tempx, tempy-6, 1); power_pos[2][1] += 0x0040; end //Erase power-up after clearing level if(clear) begin video_putbrick(tempx,tempy-6, 0); //blank 8x8 power_pos[0][1] = 0; power_pos[1][1] = 0; power_pos[2][1] = 0; end end if(power_pos[0][2]) //1 UP begin tempx = (char)(power_pos[1][2]>>8); //y-coordinate of power up tempy = (char)((power_pos[2][2]>>8)+6); //x-coordinate of power up //Algorithm will replace a brick if the power-up draws over it if((tempx >= 5)&&(tempx <= 123)&&((tempy-6) <= 48)&&((tempy-6) >= 17)) //check only if necessary begin temp = brick_pos[((tempy-6)-17)>>3][(tempx-4)>>3]; if(temp != 0) video_putbrick(((((tempx-4)>>3)<<3)+4), (((((tempy-6)-17)>>3)<<3)+17), temp); end //Power-up has reached the paddle height if(tempy == p1y) begin //power up is in between paddle width if(((tempx+8) >= p1x) && (tempx <= (p1x+p1_width))) life++; //Increases Life by 1 else if((player_num == 2)&&((tempx+8) >= p2x)&&(tempx <= (p2x+p2_width))) life++; //Increases Life by 1 video_putbrick(tempx,tempy-6, 0); //blank 8x8 power_pos[0][2] = 0; power_pos[1][2] = 0; power_pos[2][2] = 0; end else //Has not reached bottom, re-draw powerup and erase old one begin video_putpower(tempx, tempy-6, 2); power_pos[2][2] += 0x0040; end //Erase power-up after clearing level if(clear) begin video_putbrick(tempx,tempy-6, 0); //blank 8x8 power_pos[0][2] = 0; power_pos[1][2] = 0; power_pos[2][2] = 0; end end //Print out number of lives remaining in top left corner //If mode == 1 (competitive mode) print player 1 & 2's lives if(mode == 0) begin sprintf(ts,"LIVESQ%d",life); video_putsmalls(4,5,ts); if(life == 0) clear = 1; //Non-Competitive Mode, No lives left sprintf(ts, "SCOREQ"); video_putsmalls(4,93,ts); sprintf(ts,"%d00", points); video_putsmalls(32,93,ts); end else if(mode == 1) begin sprintf(ts,"LIVESQ%d",life); video_putsmalls(4,93,ts); sprintf(ts,"LIVESQ%d",life2); video_putsmalls(4,5,ts); if(life == 0) //Player 1 lost competitive mode begin sprintf(ts,"LOSE"); video_putsmalls(108,93,ts); clear = 1; end else if(life2 == 0) //Player 2 lost competitive mode begin sprintf(ts,"LOSE"); video_putsmalls(108,5,ts); clear = 1; end end end //end if(mode==0||1) else if(mode == 2) //NEW KNOCKOUT MODE begin if(b1_activate) begin video_pt(x1,y1,0); //erase old ball 1 x1pos += v1x; y1pos += v1y; //if PLAYER 1 paddle is hit, change y velocity appropriately if((y1 == p1y-1)||(y1 == p1y)||(y1 == p1y+1)||(y1 == p1y+2)) begin //paddle is of type int because of overflow in a char //paddle is used to calculate length of paddle in int //temp is the char value. If overflows, set to max width of 124 to ensure a ball hits paddle paddle = (int)((int)p1x+(int)p1_width); if(paddle <= 124) temp = (char)paddle; else temp = 124; if((x1 >= p1x)&&(x1 <= temp)&&(y1 > 70)) //Ball is within width of paddle 1 begin v1x += (x1pos - (p1_posx+(((int)p1_width<<8)>>1)))>>4; v1y = -v1y; //change y velocity sound_counter2 = 9200; //Play sound tone = 6; end end //if PLAYER 2 paddle is hit, change y velocity appropriately else if((y1 == p2y-1)||(y1 == p2y)||(y1 == p2y+1) || (y1 == (p2y+2))) begin paddle = (int)((int)p2x+(int)p2_width); if(paddle <= 124) temp = (char)paddle; else temp = 124; if((x1 >= p2x)&&(x1 <= temp)&&(y1 <= 30)) begin v1x += (x1pos - (p2_posx+(((int)p2_width<<8)>>1)))>>4; v1y = -v1y; //change y velocity sound_counter2 = 9200; //Play sound tone = 6; end //if((x1 >= p2x)&&(x1 <= temp)) end //else if((player_num == 2)&&((y1 ==... //Implement a terminal velocity for the ball @ -> 1 pixel/frame if (abs(v1x) >=0x0100) begin if(v1x > 0) v1x = 0x0100; else v1x = -0x0100; end //Hit boundaries check if((x1 >= 124)||(x1 <= 1)) v1x = -v1x; if(y1 <= 12) v1y = -v1y; if(y1 >= 88) v1y = -v1y; //Determine if ball is within brick matrix on screen, only check if it is within this region, otherwise pointless if(((x1 >= 2)&&(x1 <= 124)) && ((y1 <= 20)||(y1 >= 78))) begin tempx = (x1-4)>>3; if(y1 >= 78) tempy = (y1-72)>>3; else tempy = (y1-13)>>3; temp = protect_brick[tempy][tempx]; if(video_set(x1,y1)&&(temp == 1)) begin v1y = -v1y; sound_counter2 = 9200; //Produce a sound tone = 6; if((tempy == 0)&&(b2_count != 0)) b2_count--; else if(b1_count != 0) b1_count--; protect_brick[tempy][tempx] = 0; //Remove in matrix if(tempy == 0) video_putbrick((tempx<<3)+4, (tempy<<3)+13, 0); //Remove on screen else video_putbrick((tempx<<3)+4, (tempy<<3)+72, 0); end //if(video_set(x1,y1)&&(s > 0)) end //((x1 >= 5)&&(x1 <= 123)&&(y1 <= 48)&&(y1 >= 17)) video_pt(x1,y1,1); end if(b2_activate) begin video_pt(x2,y2,0); //erase old ball 1 x2pos += v2x; y2pos += v2y; //if paddle is hit, change x velocity appropriately if((y2 == p1y-1)||(y2 == p1y)||(y2 == p1y+1)||(y2 == p1y+2)) begin paddle = (int)((int)p1x+(int)p1_width); if(paddle <= 124) temp = (char)paddle; else temp = 124; if((x2 >= p1x)&&(x2 <= temp)&&(y2 > 70)) begin v2x += (x2pos - (p1_posx+(((int)p1_width<<8)>>1)))>>4; v2y = -v2y; //change y velocity sound_counter2 = 9200; //Produce a sound tone = 6; end end else if((y2 == p2y-1)||(y2 == p2y)||(y2 == p2y+1) || (y2 == (p2y+2))) begin paddle = (int)((int)p2x+(int)p2_width); if(paddle <= 124) temp = (char)paddle; else temp = 124; if((x2 >= p2x)&&(x2 <= temp)&&(y2 <= 30)) begin v2x += (x2pos - (p2_posx+(((int)p2_width<<8)>>1)))>>4; v2y = -v2y; //change y velocity sound_counter2 = 9200; //Produce a sound tone = 6; end end if (abs(v2x) >=0x0100) begin if(v2x > 0) v2x = 0x0100; else v2x = -0x0100; end if((x2 >= 124)||(x2 <= 1)) v2x = -v2x; if(y2 <= 12) v2y = -v2y; //If the ball hits the bottom, it is inactivated (Player 1 loses life) if(y2 >= 88) v2y = -v2y; //Determine if a brick is hit by the second ball and erase the brick when appropriate if(((x2 >= 2)&&(x2 <= 124)) && ((y2 <= 20)||(y2 >= 78))) begin tempx = (x2-4)>>3; if(y2 >= 78) tempy = (y2-72)>>3; else tempy = (y2-13)>>3; temp = protect_brick[tempy][tempx]; if(video_set(x2,y2)&&(temp == 1)) begin v2y = -v2y; sound_counter2 = 9200; //Produce a sound tone = 6; if((tempy == 0)&&(b2_count != 0)) b2_count--; else if(b1_count != 0) b1_count--; protect_brick[tempy][tempx] = 0; //Remove in matrix if(tempy == 0) video_putbrick((tempx<<3)+4, (tempy<<3)+13, 0); //Remove on screen else video_putbrick((tempx<<3)+4, (tempy<<3)+72, 0); end //if(video_set(x1,y1)&&(s > 0)) end video_pt(x2,y2,1); //draw ball with new position end //end if(b2_activate) if(b2_count == 9) //Used to delete the 2-digit printout so 1 digit can be displayed (not 90 for '9') begin sprintf(ts,"QQQQQQQQQ"); video_putsmalls(4,5,ts); end sprintf(ts,"BRICKSQ%d", b2_count); video_putsmalls(4,5,ts); if(b1_count == 9) begin sprintf(ts,"QQQQQQQQQ"); video_putsmalls(4,93,ts); end sprintf(ts,"BRICKSQ%d", b1_count); video_putsmalls(4,93,ts); if((b2_count == 0)||(b1_count == 0))clear = 1; end end //line 231 and !endgame end //while /******************LEVEL END CONDITIONS********************/ if((life != 0)&&(mode == 0)&&(brick_count == 0)) //Level successfully cleared begin sound_counter2 = 3000; //Produces a winner sound tone = 8; for(a = 0; a < 1300; a++) begin for(b = 0; b < 100; b++) begin if(LineCount == 231) begin if(h != 9) begin sprintf(ts,"LEVELQ%d", h+1); video_puts(20,35,ts); sprintf(ts,"CLEAR"); video_puts(70,35,ts); end else begin sprintf(ts,"WINNER"); video_puts(50,35,ts); end end end end if(h == 9) h = -1; else h++; b2_activate = 0; end else if((mode == 0)&&(life == 0)) //Not successful begin sound_counter2 = 6001; //Produce an unsuccessful sound tone = 7; for(a = 0; a < 1300; a++) begin for(b = 0; b < 100; b++) begin if(LineCount == 231) begin sprintf(ts,"GAMEOVER"); video_puts(40,35,ts); end end end h = -1; points = 0; end else if(mode == 0) //Both Balls De-activated begin sound_counter2 = 6001; //Produce an unsuccessful sound tone = 7; for(a = 0; a < 1300; a++) begin for(b = 0; b < 100; b++) begin if(LineCount == 231) begin sprintf(ts,"TRYQAGAIN"); video_puts(40,35,ts); end end end b2_activate = 0; end else if( ((mode == 1)&&(life == 0)) || ((mode == 2)&&(b1_count == 0))) //Player 2 won (competitive or knockout mode) begin sound_counter2 = 3000; tone = 8; for(a = 0; a < 1300; a++) begin for(b = 0; b < 100; b++) begin if(LineCount == 231) begin sprintf(ts,"P2QWON"); video_puts(40,35,ts); end end end h = -1; points = 0; end else if( ((mode == 1)&&(life2 == 0)) || ((mode == 2)&&(b2_count == 0))) //Player 1 won (competitive or knockout mode) begin sound_counter2 = 3000; tone = 8; for(a = 0; a < 1300; a++) begin for(b = 0; b < 100; b++) begin if(LineCount == 231) begin sprintf(ts,"P1QWON"); video_puts(40,35,ts); end end end h = -1; points = 0; end /*****************************************************************/ //disable sleep mode MCUCR = 0b00000000; #asm ("cli"); //Erase screen for(a = 0; a < 1600; a++) screen[a] = 0; //RE-DRAW BORDERS AROUND SIDES OF SCREEN //side lines video_line(0,0,0,99,1); video_line(width,0,width,99,1); //top line & bottom lines video_line(0,0,width,0,1); video_line(0,99,width,99,1); video_line(0,11,width,11,1); video_line(0,89,width,89,1); video_pt(x1,y1,0); video_pt(x2,y2,0); video_line(1,p1y-1, width-1,p1y-1,0); video_line(1,p1y, width-1,p1y,0); video_line(1,p2y-1, width-1,p2y-1,0); video_line(1,p2y, width-1,p2y,0); end //while(h < 10) end //main