Code

 

 

//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