//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
//C.0 is sound
#pragma regalloc- //I allocate the registers myself
#pragma optsize- //optimize for speed
#include <Mega32.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <delay.h>
//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
#define T0reload 256-60
//keypad
#define maxkeys 16
//new code
#define XMAX 106 // maximum x value of the screen
#define YMAX 99 // maximum y value of the screen
#define maxAst 4 // maximum number of asteroids on the screen
#define astRate 4 //
speed of asteroids (larger the value, slower the speed)
#define monRate 2 // speed of monsters (larger the value, slower
the speed)
#define astFreq 10 // frequency of the appearance of asteroids
// the bigger, the less frequent
#define monFreq 200 // frequency of the appearance of monsters
#define maxMon 3 // maximum number of monsters on the screen
#define maxAmmo 3 // maximum number of ammos on the screen
#define ammoSpeed 0 // speed
of an ammo
#define initLife 3 // number of lives user have
// State constants
// SqState
#define SQUARE 0
#define DIAMOND 1
// gameState
#define RUNNING 0
#define DEAD 1
#define GAMEOVER1 2
#define GAMEOVER2 3
#define GAMEOVER3 4
#define REV1 5
#define REV2 6
#define REV3 7
#define CALIB1 8
#define CALIB2 9
unsigned char key, butnum;
//revised version:
//1 - 9, 0, A, B, C, D, *,
#
flash unsigned char keytbl[16]={0xee,
0xde, 0xbe, 0xed, 0xdd, 0xbd,
0xeb, 0xdb, 0xbb, 0xd7, 0x7e,
0x7d, 0x7b, 0x77, 0xe7, 0xb7};
//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;
int time;
//animation
char x,
y, vx, vy;
//Point plot lookup table
flash char pos[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
char screen[1600], t;
//new variables
// specifies whether or not
the fighter is moving towards the x or y
// direction
bit xmotion, ymotion;
// specifies which direction
the fighter is moving
bit xincr, yincr;
// variables for specifying
the speed of the fighter
unsigned char xcntmax, ycntmax;
// counting variable
unsigned char xcnt, ycnt;
// current x and y position
of the fighter
unsigned char xpos, ypos;
// State variables
char randomState;
char inputState;
char gameState;
// seed of rand()
char seed;
// random variables
unsigned int random, random2,
random3, random4;
// x and y position for array
of asteroids
char xast[maxAst], yast[maxAst];
// whether each asteroid is
present or not
char astPresent[maxAst];
// counter variables to help
generating asteroids
char astCnt;
char astMoveCnt[maxAst];
// variables used for calculation
char vmon,
vstone, vchar;
bit monflag;
// counter variables to help
generating monsters
char monMoveCnt[maxMon];
char monPresent[maxMon];
// position of monsters
char xmon[maxMon], ymon[maxMon];
// movement directions of monsters
char xmonincr[maxMon], ymonincr[maxMon];
// positions for ammos
unsigned char xammo[maxAmmo],
yammo[maxAmmo];
// indicate the press of button
'D'
bit shoot;
// to let the user to recognize
the button only once for continuous pushing
bit buttonPress;
char ammoPresent[maxAmmo];
// indicate the next ammo available
char nextAmmo;
// the voltage got from ADC
unsigned int Ain;
// x and y voltage
char yvolt;
char xvolt;
//score
unsigned int score;
unsigned int tempscore;
unsigned int temprmd;
// string variable
char teststr[10];
// variables for generating
the series of squares and diamonds after the fighter
unsigned int sqWidth;
int xmin,
ymin, xmax, ymax;
bit sqState;
int a;
int t1;
// the counter which increments
every frame, used to enable alternate movement of monsters or asteroids
char univCnt;
// no. of lives
char life;
// calibration variables, to
specify the voltage level for each direction movement
char LEFT1, LEFT2, RIGHT1, RIGHT2, UP1, UP2, DOWN1, DOWN2;
char calibState;
// voltage level when the device
is in horizontal position.
char xstdvolt, ystdvolt;
//fighter
//5X4
flash char fighter[2][7]={
//normal
0b00000000,
0b00010000,
0b00111000,
0b00111000,
0b01111100,
0b00010000,
0b00000000,
//explode
0b00000000,
0b00010000,
0b00111000,
0b01111100,
0b00010000,
0b00010000,
0b01010000};
/*
//monster pattern
*/
flash char mon[2][8]={
//type I
0b11111111,
0b10011001,
0b10011001,
0b11111111,
0b10000001,
0b10000001,
0b11000011,
0b11111111,
//type II
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111};
//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,
//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,
//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
//start the Horizontal sync pulse
PORTD = syncON;
//count timer 0 at 1/usec
TCNT0=0;
//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<ScreenBot && 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
// to include the "blank" character
if (str[i] == 0x20)
video_smallchar(x,y,0xc);
else
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
//==================================
//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++)
{
//check for out-of-bound condition
if(!(x > XMAX || x < 0 || y > YMAX || y < 0))
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
//==================================
//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
//draw the fighter on the screen
//(x,y) is the top left position
void drawFighter(char x, char
y)
begin
v7 = x;
for (v6=0;v6<7;v6++)
begin
v1 = fighter[0][v6];
v8 = y+v6;
//fighter is a bitmap
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);
end
end
//moves the asteroid to the
next position, which is down
//the screen, i.e. y+1
//(x,y) is the bottom left
position
void moveAst( char x, char
y)
begin
v8 = x + 15;
// an asteroid is not a bitmap. It is a square
// made up of lines. For every step the asteroid moves,
// the function only has to draw the next line and
// delete the top line.
// drawing the new line
if( (y+1 <= YMAX-1) && ( y+1 > 0 ) )
video_line( x+2, y+1, v8-2, y+1, 1 );
// the asteroid is dented towards the top and bottom.
// therefore as the asteroid moves down the denting
// part has to be updated as well.
if( (y <= YMAX-1) && ( y > 0 ) )
{
video_pt( x+1, y, 1 );
video_pt( x+2, y, 1 );
video_pt( v8-1, y, 1 );
video_pt( v8-2, y, 1 );
}
if( (y - 1 <= YMAX-1) && ( y-1 > 0 ) )
{
video_pt( x, y-1, 1 );
video_pt( x+1, y-1, 1 );
video_pt( v8, y-1, 1 );
video_pt( v8-1, y-1, 1 );
}
if( (y-13 <= YMAX-1) && (y - 13 > 0) )
{
video_pt( x, y-13, 0 );
video_pt( v8, y-13, 0 );
}
if( (y-14 <= YMAX-1) && (y - 14 > 0) )
{
video_pt( x+1, y-14, 0 );
video_pt( v8-1, y-14, 0 );
}
// deleting the top line
if( (y-15 <= YMAX-1) && (y - 15 > 0) )
{
video_line( x+1, y-15, v8-2, y-15, 0 );
}
end
//updates the monster position
at (x,y) towards the direction
//specified by xdir and ydir.
// 0 -- decrement by 1
// 1 -- increment by 1
// 2 -- no move
//(x,y) is the upper left position
void moveMon( char x, char
y, char xdir, char ydir )
begin
v7 = x;
// moving towards the right of the screen.
// the leftmost line is then deleted.
if( xdir == 1 )
{
if( x < XMAX-8 )
{
v7 = x + 1;
for(v6=0; v6<8; v6++)
video_pt(x, y+v6, 0);
}
}
// moving towards the left of the screen.
// the rightmost line is then deleted.
else if( xdir == 0 )
{
if( x > 1 )
{
v7 = x - 1;
for(v6=0; v6<8; v6++)
video_pt(x+7, y+v6, 0);
}
}
vchar = y;
// moving towards the bottom of the screen
// the top line is then deleted.
if( ydir == 1 )
{
if( y < YMAX-8 )
{
vchar = y + 1;
for(v6=0; v6<8; v6++)
video_pt(x+v6, y, 0);
}
}
// moving towards the top of the screen
// the bottom line is then
deleted
else if( ydir == 0 )
{
if( y > 1 )
{
vchar = y - 1;
for(v6=0; v6<8; v6++)
video_pt(x+v6, y+7, 0);
}
}
// drawing the monster.
// the monster is a bitmap
for (v6=0;v6<8;v6++)
begin
v1 = mon[0][v6];
v8 = vchar+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
// clears the monster at position
(x,y)
// (x,y) is the top left position
of the monster
void clearMon(char x, char
y)
{
for(v6 = 0; v6<8; v6++)
begin
v8 = y+v6;
for(v7 = 0; v7<8; v7++)
video_pt(x+v7, v8, 0);
end
}
// draws an ammo on the screen
at (x,y)
//(x,y) is the top pixel
void drawAmmo(char x, char
y)
{
// an ammo is a string of 5 vertical pixels with
// the middle pixel being black and the rest
// being white
for(v6 = 0; v6<5; v6++)
{
if(y+v6 < ypos)
{
if(v6 == 2)
video_pt(x, y+v6, 0);
else
video_pt(x, y+v6, 1);
}
}
// assume it's a moving ammo, therefore we need
// to delete the lowest pixel of the last ammo
if(y+5 < ypos)
video_pt(x,y+5,0);
}
// clears the ammo on the screen
at (x,y)
// (x,y) is the top pixel
void clearAmmo(char x, char
y)
{
video_pt(x,y,0);
video_pt(x,y+1,0);
video_pt(x,y+2,0);
video_pt(x,y+3,0);
video_pt(x,y+4,0);
}
void volt( char portNo )
{
//init the A to D converter
//channel zero/ left adj /int Aref
//!!!DISCONNECT Aref jumper!!!!
//enable ADC and set prescaler to 1/64*8MHz=125,000
//and set int enable
ADCSR = 0b11000111;
while(1)
{
//get Ain until the conversion has completed
if(ADCSR.6 == 1)
{
Ain = ADCH;
}
else
break;
}
}
// code for initializing the
variables
// used at the start of every
game
void initialize(void)
{
// variable initialization
xpos = 50;
ypos = 80;
xcnt = 0;
ycnt = 0;
randomState = 0;
astCnt = 0;
for( v5 = 0; v5 < maxAst; v5++ )
astMoveCnt[v5] = 0;
for( v5 = 0; v5 < maxMon; v5++ )
monMoveCnt[v5] = 0;
shoot = 0;
nextAmmo = 0;
sqWidth = 30;
sqState = SQUARE;
for(v2 = 0; v2 < maxAmmo; v2++)
{
ammoPresent[v2] = 0;
}
seed = 7;
for( v2 = 0; v2 < maxAst; v2++ )
astPresent[v2] = 0;
for(v2 = 0; v2 < maxMon; v2++)
monPresent[v2] = 0;
//accelerometer
Ain = 0;
inputState = 0;
yincr = 2;
xincr = 2;
ymotion = 0;
xmotion = 0;
univCnt = 0;
// displays score and number of lives left
// on the screen
sprintf(teststr, "SCORE");
video_putsmalls(108, 20, teststr);
sprintf(teststr, "%04d", score);
video_putsmalls(112, 30, teststr);
sprintf(teststr, "LIFE");
video_putsmalls(108, 50, teststr);
sprintf(teststr, "%01d", life);
video_putsmalls(116, 60, teststr);
}
//==================================
// set up the ports and timers
void main(void)
begin
buttonPress = 0;
gameState = CALIB1;
//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 ports
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
//init timer 0 to 1/uSec
TCCR0 = 2;
//initialize synch constants
LineCount = 1;
syncON = 0b00000000;
syncOFF = 0b00100000;
//init animation
x = 64;
y=50;
vx=1;
vy=1;
//enable sleep mode
MCUCR = 0b10000000;
#asm ("sei");
//The following loop executes once/video line during lines
//1-230, then does all of the frame-end processing
while(1)
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 )
begin
// a counter which increments every frame
univCnt++;
//get kepad result
//get lower nibble
DDRC = 0x0f;
PORTC = 0xf0;
delay_us(5);
key = PINC;
//get upper nibble
DDRC = 0xf0;
PORTC = 0x0f;
delay_us(5);
key = key | PINC;
//find matching keycode in keytbl
if (key != 0xff)
{
for (butnum=0; butnum<maxkeys;
butnum++)
{
if (keytbl[butnum]==key)
break;
}
if (butnum==maxkeys) butnum=0;
else butnum++; //adjust by one to make range 1-16
}
else butnum=0;
PORTB = ~ butnum ;
//end keypad
switch ( gameState )
{
case RUNNING:
//keypad specific code
if(butnum == 14)
shoot = 1;
else
{
//to ensure that the button is detected once for continuous
pressing
buttonPress = 0;
shoot = 0;
}
//end keypad code
// code for drawing the fighter
//x-axis movement of the fighter
//The following statement is used to avoid the fighter to
move in x-
//direction with a frequency higher than xcntmax no. of
frames
if( xcnt >= xcntmax )
{
if( xmotion == 1 )
{
xcnt = 0;
if( xincr )
{
if( xpos < XMAX - 7 )
xpos++;
}
else
{
if( xpos > 1 )
xpos--;
}
}
}
else
xcnt++;
//y-axis movement of the fighter
if( ycnt >= ycntmax )
{
if( ymotion == 1 )
{
ycnt = 0;
if( yincr )
{
if( ypos < YMAX - 7 )
ypos++;
}
else
{
if( ypos > 1 )
ypos--;
}
}
}
else
ycnt++;
//draw the fighter
drawFighter( xpos, ypos );
//generating random numbers
//change the seed
if(xmotion)
{
seed = seed + 7;
srand( seed );
}
// code for generating randomness for which and where the
asteroids
// or the monsters appear
// each random number is generated every frame
switch( randomState )
{
//which asteroid
case 0:
random = rand();
random = random % astFreq;
// the last condition is used to make sure that two
asteroids won't stick to each other
if( ( random < maxAst ) && ( astPresent[random]
== 0 ) &&
( astCnt > (15 * astRate ) ) )
{
astCnt = 0;
astPresent[random] = 1;
astMoveCnt[random] = 0;
xast[random] = random2;
yast[random] = 0;
}
else
astCnt++;
randomState = 1;
break;
//where does the asteroid appear
case 1:
random2 = rand();
random2 = (random2 % (XMAX - 17)) + 1;
randomState = 2;
break;
// which monster
case 2:
random3 = rand();
random3 = random3 % monFreq;
if( ( random3 < maxMon ) && ( monPresent[random3]
== 0 ) )
{
monPresent[random3] = 1;
monMoveCnt[random3] = 0;
// appear from the top portion of the wall on the
left
if( random4 <= 30 )
{
xmon[random3] = 1;
ymon[random3] = random4;
}
// appear from the top portion of the wall on the
right
else if( random4 >= (XMAX + 31) )
{
xmon[random3] = XMAX - 9;
ymon[random3] = random4 - (XMAX + 30);
}
// appear from the top
else
{
xmon[random3] = random4 - 40;
ymon[random3] = 1;
}
}
randomState = 3;
break;
// where the monster appear on the screen
case 3:
random4 = rand();
random4 = random4 % (XMAX + 52) + 1;
randomState = 0;
break;
}
//move asteroid
for( v4 = 0; v4 < maxAst;
v4++ )
{
if( (astPresent[v4] == 1) && ( astMoveCnt[v4]
>= astRate ) &&
(univCnt % 4 == v4 % 4) )
{
moveAst( xast[v4], yast[v4] );
yast[v4]++;
if( yast[v4] >= YMAX + 15 )
{
astPresent[v4] = 0;
}
astMoveCnt[v4] = 0;
}
else
astMoveCnt[v4]++;
}
//detecting crash of the fighter into asteroids
for(v5 = 0; v5 < 7; v5++)
{
// checks whether the line of pixels are colored at the
direction
// where the fighter is moving
// checks if the rightmost pixels are colored if the fighter
is moving
// right
if(xmotion && xincr && video_set(xpos+7,ypos+v5)
&& xpos<(XMAX - 7))
{
gameState = DEAD;
}
// checks if the leftmost pixels are colored if the fighter
is moving
// left
else if(xmotion && !xincr && video_set(xpos-1,ypos+v5)
&& xpos>1)
{
gameState = DEAD;
}
// checks if the bottom pixels are colored if the fighter
is
//moving down
if(ymotion && yincr && video_set(xpos+v5,ypos+7)
&& ypos<(YMAX-7))
{
gameState = DEAD;
}
// checks if the top pixels are colored if the fighter
is moving up
else if(ymotion && !yincr && video_set(xpos+v5,ypos-1)
&& ypos>1)
{
gameState = DEAD;
}
// if the fighter is not moving it is sufficient to only
check
// whether the four corner pixels are colored
if(!ymotion && !xmotion && (video_set(xpos+1,ypos+1)
||
video_set(xpos+6,ypos+1) || video_set(xpos+6,ypos+6)
||
video_set(xpos+1,ypos+6) ))
{
gameState = DEAD;
}
}
// code for deciding which direction the monsters should
move
for( vmon = 0; vmon < maxMon; vmon++ )
{
if( monPresent[vmon] == 1 )
{
// first detects whether the fighter hits a monster
if( ( ( xmon[vmon] - xpos <= 6 ) || ( xpos - xmon[vmon]
<= 7 ) ) &&
( ( ymon[vmon] - ypos <= 8 ) || ( ypos - ymon[vmon]
<= 8 ) ) )
{
gameState = DEAD;
}
else if( monMoveCnt[vmon] <= monRate )
{
monflag = 0;
// checks whether there are colored pixels on top
of monsters,
// since asteroids only move down, the monsters should
detect
// whether there are asteroids on top of them. This
also checks
// whether the monsters hit the boundary
for( vstone
= 0; vstone < 8; vstone++)
{
if( video_set(xmon[vmon]+vstone,ymon[vmon]-1) )
{
monflag = 1;
break;
}
}
if( monflag )
{
// the monster disappears if it is at the boundary
if( (xmon[vmon] < 1) || (xmon[vmon] > XMAX
- 8) ||
(ymon[vmon] < 1) || (ymon[vmon] > YMAX
- 8) )
{
monPresent[vmon] = 0;
}
// asteroid on top, the monster should move down
else
{
moveMon( xmon[vmon], ymon[vmon], 2, 1 );
ymon[vmon]++;
}
}
}
}
}
//draw monster
for( vmon = 0; vmon < maxMon; vmon++ )
{
// the monster disappears at the boundary
if( monPresent[vmon]
== 1 && ( (xmon[vmon] >= XMAX - 8) ||
(ymon[vmon] >= YMAX - 8) ) )
monPresent[vmon] = 0;
else if( (monPresent[vmon] == 1) && (monMoveCnt[vmon]
>= monRate) &&
(univCnt % 2 == vmon % 2) )
{
//incr: 1 - incr, 0 - decr, 2 - stay
// moving towards the fighter
if( xpos > xmon[vmon] + 2 )
xmonincr[vmon] = 1;
else
xmonincr[vmon] = 0;
// stops chasing the fighter if fighter too far on top
of monster
if( ymon[vmon] > ypos + 50 )
ymonincr[vmon] = 1;
// again moving towards the fighter
else if( ypos > ymon[vmon] + 2 )
ymonincr[vmon] = 1;
else
ymonincr[vmon] = 0;
// monflag specifies the existence of an asteroid at
the direction
monflag = 0;
//avoiding asteroid
//check right direction
if( xmonincr[vmon] == 1 )
{
for( vstone = 0; vstone < 8; vstone++ )
{
if( video_set(xmon[vmon]+8,ymon[vmon]+vstone) )
{
monflag = 1;
break;
}
}
// monster keeps x position at boundary
if( xmon[vmon] >= XMAX - 8)
{
xmonincr[vmon] = 2;
}
else
{
if( monflag )
{
xmonincr[vmon] = 2;
// can't just stay there, so move up if y is also
stalled
if( ymonincr[vmon] == 2 )
ymonincr[vmon] = 0;
}
// stay at y if it is going to move up and
// there is colored pixel on top
else if( ( ymonincr[vmon] == 0 ) &&
( video_set(xmon[vmon]+8, ymon[vmon]-1)
) )
ymonincr[vmon] = 2;
// stay at y if it is going to move down and
// there is colored pixel at the bottom
else if( ( ymonincr[vmon] == 1 ) &&
( video_set(xmon[vmon]+8, ymon[vmon]+8)
) )
ymonincr[vmon] = 2;
}
}
//checking left
monflag = 0;
if( xmonincr[vmon] == 0 )
{
for( vstone = 0; vstone < 8; vstone++ )
{
if( video_set(xmon[vmon]-1,ymon[vmon]+vstone) )
{
monflag = 1;
break;
}
}
// stay at x at boundary
if( xmon[vmon] <= 1 )
{
xmonincr[vmon] = 2;
}
else
{
if( monflag )
{
xmonincr[vmon] = 2;
// can't just stay there, so move up if y is also
stalled
if( ymonincr[vmon] == 2 )
ymonincr[vmon] = 0;
}
// stay at y if it is going to move up and
// there is colored pixel on top
else if(
( ymonincr[vmon] == 0 ) &&
( video_set(xmon[vmon]-1,ymon[vmon]-1)
) )
ymonincr[vmon] = 2;
// stay at y if it is going to move down and
// there is colored pixel at the bottom
else if( ( ymonincr[vmon] == 1 ) &&
( video_set(xmon[vmon]-1,ymon[vmon]+8)
) )
ymonincr[vmon] = 2;
}
}
//checking top
monflag = 0;
if( ymonincr[vmon] == 0 && !( ( ( xmon[vmon]
- xpos <= 6 ) ||
( xpos - xmon[vmon] <= 7 ) ) && ( ymon[vmon]
- ypos <= 6 ) ) )
{
for( vstone
= 0; vstone < 8; vstone++)
{
// if there is asteroid 2 pixels on top, do not
go up
if( video_set(xmon[vmon]+vstone,ymon[vmon]-2) )
{
monflag = 1;
break;
}
}
if( monflag )
ymonincr[vmon] = 2;
}
monflag = 0;
for( vstone = 0; vstone < 8; vstone++)
{
// if there is asteroid right above, move down to
avoid
// hitting asteroid next step
if( video_set(xmon[vmon]+vstone,ymon[vmon]-1) )
{
monflag = 1;
break;
}
}
if( monflag )
ymonincr[vmon] = 1;
//checking bottom
monflag = 0;
if( ymonincr[vmon] == 1 )
{
for( vstone = 0; vstone < 8; vstone++ )
{
if( video_set(xmon[vmon]+vstone,ymon[vmon]+9) )
{
monflag = 1;
break;
}
}
if( monflag )
ymonincr[vmon] = 2;
}
// monsters disappear at boundary
if( (xmon[vmon] < 1) || (xmon[vmon] > XMAX - 8)
||
(ymon[vmon] < 1) || (ymon[vmon] > YMAX - 8)
)
{
monPresent[vmon] = 0;
}
// draw it!!
else
{
moveMon( xmon[vmon], ymon[vmon], xmonincr[vmon], ymonincr[vmon]
);
}
// update array
if( xmonincr[vmon] == 1 )
xmon[vmon]++;
else if( xmonincr[vmon] == 0)
xmon[vmon]--;
if( ymonincr[vmon] == 1 )
ymon[vmon]++;
else if( ymonincr[vmon]
== 0)
ymon[vmon]--;
// monster disappears at boundary
if( ymon[vmon] >= YMAX-9 )
{
monPresent[vmon] = 0;
clearMon(xmon[vmon],ymon[vmon]);
}
monMoveCnt[vmon] = 0;
} // end else
if
else
{
monMoveCnt[vmon]++;
}
} // end for
// ammo
// code for adding
ammo on shoot
// buttonPress to avoid multiple shoot if user hold down
button
if(!buttonPress)
{
//draw ammo
if(shoot)
{
if( ammoPresent[nextAmmo] == 0 && ypos >
7)
{
// +3 to appear from the middle of fighter
xammo[nextAmmo] = xpos+3;
// +6 to avoid the fighter being hit by its own ammo
yammo[nextAmmo] = ypos-6;
shoot = 0;
buttonPress = 1;
ammoPresent[nextAmmo] = 1;
nextAmmo++;
if(nextAmmo == maxAmmo)
nextAmmo = 0;
}
}
}
// code for updating ammo
for(v5 = 0; v5 < maxAmmo; v5++)
{
if(ammoPresent[v5] == 1) //&& ((xammo[v2] &
0xff) != 0xff) )
{
if( (yammo[v5] > 1) && (video_set( xammo[v5],yammo[v5]-1
) == 0) )
{
// ammo only goes upwards
yammo[v5]--;
drawAmmo(xammo[v5],yammo[v5]);
}
else
{
// clear ammo if it hits any colored pixel
clearAmmo(xammo[v5],yammo[v5]);
ammoPresent[v5] = 0;
}
}
}
//check if the monster is hit by a bullet
for( vmon = 0; vmon < maxMon; vmon++ )
{
if( monPresent[vmon] == 1 )
{
for(v5=0; v5<maxAmmo; v5++)
{
// checks whether the ammo position is within any
monster
if((xammo[v5]>=xmon[vmon]) && (xammo[v5]<=xmon[vmon]+7)
&&
(yammo[v5]>=ymon[vmon]) && (yammo[v5]<=ymon[vmon]+8)
&&
(ammoPresent[v5]==1))
{
clearAmmo( xammo[v5],yammo[v5]);
ammoPresent[v5]=0;
clearMon( xmon[vmon], ymon[vmon]);
monPresent[vmon] = 0;
// awards 10 points to the user for fallen monster
if( score < 1000 )
score += 10;
tempscore = score / 10;
temprmd = tempscore % 10;
// prints new score on screen
// only draw the digits updated
sprintf(teststr, "%01d", temprmd);
video_putsmalls(120, 30, teststr);
if( temprmd == 0 )
{
tempscore = tempscore / 10;
temprmd = tempscore % 10;
sprintf(teststr, "%01d", temprmd);
video_putsmalls(116, 30, teststr);
if( temprmd == 0 )
{
sprintf(teststr, "%01d", temprmd);
video_putsmalls(112, 30, teststr);
}
}
break;
}
}
}
}
// accelerometer
// x and y each uses 2 frames to detect, totaling 4 frames
for each
// set of inputs.
// the change of ADMUX uses 1 frame by itself because otherwise
// there will be insufficient time switching between taking
x and y.
switch( inputState )
{
case 0:
volt( 1 ); //port 1 is yellow wire
xvolt = (char) (Ain % 256);
// moving towards -x faster
if( xvolt > LEFT2 )
{
xmotion = 1;
xincr = 0;
xcntmax = 0;
}
// moving towards -x slower
else if( xvolt > LEFT1 )
{
xmotion = 1;
xincr = 0;
xcntmax = 1;
}
// moving towards +x faster
else if( xvolt
< RIGHT2 )
{
xmotion = 1;
xincr = 1;
xcntmax = 0;
}
// moving towards +x slower
else if( xvolt < RIGHT1 )
{
xmotion = 1;
xincr = 1;
xcntmax = 1;
}
// no change in x-direction
else
{
xmotion = 0;
}
inputState = 1;
break;
case 1:
// change the port 0
ADMUX = 0b11100000;
inputState = 2;
break;
case 2:
volt( 0 ); //port 0 is blue wire
yvolt = (char) (Ain % 256);
// moving towards -y faster
if( yvolt > UP2 )
{
ymotion = 1;
yincr = 0;
ycntmax = 0;
}
// moving towards -y slower
else if( yvolt > UP1 )
{
ymotion = 1;
yincr = 0;
ycntmax = 1;
}
// moving towards +y faster
else if( yvolt < DOWN2 )
{
ymotion = 1;
yincr = 1;
ycntmax = 0;
}
// moving towards +y slower
else if( yvolt
< DOWN1 )
{
ymotion = 1;
yincr = 1;
ycntmax = 1;
}
else
{
ymotion = 0;
}
inputState = 3;
break;
case 3:
//change to port 0
ADMUX = 0b11100001;
inputState = 0;
break;
}//switch accel
break; //gameState = RUNNING
// the state where the fighter's hit by monster or asteroid
// i.e. fighter dead
case DEAD:
// when the fighter is dead, the program draws a square
and a diamond
// in alternate frames and each time enlarging their side
lengths
// till the squares and diamonds fill the gaming area.
switch(sqState)
{
// a square is drawn
case SQUARE:
//sq
t1 = (sqWidth / 2) + 3;
xmin = xpos - t1;
xmax = xpos + t1;
ymin = ypos - t1;
ymax = ypos + t1;
if( xmin <= 1 )
xmin = 1;
if( xmax >= XMAX )
xmax = XMAX;
if( ymin <= 1 )
ymin = 1;
if( ymax >= YMAX )
ymax = YMAX;
video_line( xmin, ymin, xmax, ymin, 1 );
video_line( xmin, ymin, xmin, ymax, 1 );
video_line( xmax, ymax, xmax, ymin, 1 );
video_line( xmax, ymax, xmin, ymax, 1 );
sqState = DIAMOND;
// worst case: if the fighter dies an the corner of
the screen.
// to fill the
gaming area, we need the square width to reach
// double the maximum x value
if(sqWidth >= 2*XMAX)
{
if( life <= 1 )
{
gameState = GAMEOVER1;
}
else
{
gameState = REV1;
life--;
}
}
break;
case DIAMOND:
// diamond just consists of 4 lines drawing 5 pixels
from
// mid-point of each side.
video_line((xmin+xmax)/2,ymin-5,xmin-5,(ymin+ymax)/2,1);
video_line(xmin-5,(ymin+ymax)/2,(xmin+xmax)/2,ymax+5,1);
video_line((xmin+xmax)/2,ymax+5,xmax+5,(ymin+ymax)/2,1);
video_line(xmax+5,(ymin+ymax)/2,(xmin+xmax)/2,ymin-5,1);
if(sqWidth < 2*XMAX)
sqWidth += 10;
else
{
if( life <= 1 )
{
gameState = GAMEOVER1;
}
else
{
gameState = REV1;
life--;
}
}
sqState = SQUARE;
break;
}
break;
// it takes one frame to just clear the screen
// to avoid flicker
case GAMEOVER1:
for( a = 0; a < 1600; a++ )
screen[a] = 0x0;
gameState = GAMEOVER2;
break;
case GAMEOVER2:
// user can play another game by pressing shoot
// after game over
if(butnum == 14)
{
sprintf(teststr, " ");
video_putsmalls(48, 38, teststr);
sprintf(teststr, " ");
video_putsmalls(48, 48, teststr);
gameState = GAMEOVER3;
life = initLife;
score = 0;
initialize();
}
else
{
sprintf(teststr, "GAME OVER");
video_putsmalls(48, 38, teststr);
sprintf(teststr, "SCORE: %04d", score);
video_putsmalls(48, 48, teststr);
}
break;
case GAMEOVER3:
// draw the frame
//side lines
video_line(0,0,0,YMAX,1);
video_line(XMAX,0,XMAX,YMAX,1);
//top line & bottom lines
video_line(0,0,XMAX,0,1);
video_line(0,YMAX,XMAX,YMAX,1);
buttonPress = 1;
gameState = RUNNING;
break;
// this is the revive state. It happens if the user
// is dead and he still has lives
case REV1:
// make the whole screen white, except
the
// score area on the right
for( a = 0; a < 1600; a++ )
{
if( a % 16 <= 12 )
screen[a] = 0xff;
else if( a % 16 == 13 )
screen[a] = screen[a]
| 0b11100000;
}
gameState = REV2;
break;
// separate into several frames to avoid
// flickering
case REV2:
// make the whole screen black, except
the
// score area on the right
for( a = 0; a < 1600; a++ )
{
if( a % 16 <= 12 )
screen[a] = 0x00;
else if( a % 16 == 13 )
screen[a] = screen[a] & 0b00011111;
}
gameState = REV3;
break;
case REV3:
// initialize
initialize();
gameState = GAMEOVER3;
break;
//calibration state
case CALIB1:
sprintf(teststr, "HOLD THE CONTROLLER UP");
video_putsmalls(16, 30, teststr);
sprintf(teststr, "STRAIGHT THEN PRESS SHOOT");
video_putsmalls(16, 40, teststr);
switch (calibState)
{
// get the horizontal x-axis voltage
case 0:
ADMUX = 0b11100001;
volt(1);
xstdvolt = (char) (Ain % 256);
calibState =
1;
break;
case 1:
ADMUX = 0b11100000;
volt(0);
ystdvolt = (char) (Ain % 256);
calibState = 0;
break;
}
// takes the voltage of the accelerometer when
// the user presses shoot
if(butnum == 14)
{
for( a = 0; a < 1600; a++ )
screen[a] = 0x0;
gameState = CALIB2;
}
break;
// the value taken where the user is holding the device
// upright is the mid-point of the range.
case CALIB2:
LEFT1 = xstdvolt + 10;
LEFT2 = xstdvolt + 15;
RIGHT1 = xstdvolt - 10;
RIGHT2 = xstdvolt - 15;
UP1 = ystdvolt + 10;
UP2 = ystdvolt + 15;
DOWN1 = ystdvolt - 10;
DOWN2 = ystdvolt - 15;
gameState = GAMEOVER3;
life = initLife;
score = 0;
initialize();
break;
} //gameState switch
end //line 231
end //while
end //main