Martin Johnson / Space_Invaders_Demo

Dependencies:   STM32F3-Discovery

space_invaders.c

Committer:
MartinJohnson
Date:
2016-03-01
Revision:
0:404dae88af71

File content as of revision 0:404dae88af71:

/***************************************************************************
 * STM32 VGA demo
 * Copyright (C) 2012 Artekit Italy
 * http://www.artekit.eu
 * Written by Ruben H. Meleca
 
### space_invaders.c
 
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

***************************************************************************/

#include "stm32f30x.h"
#include "sys.h"
#include "video.h"
#include "gdi.h"
#include "space_invaders.h"
//#include <string.h>
//#include <stdio.h>
//#include <stdlib.h>

extern volatile u32    sysTicks;




extern u8				siLogo[VID_VSIZE][VID_HSIZE];

//extern volatile u32		sysTicks;

const u8 	siBadBoys99[] = {	0x00, 0x00,
								0x00, 0x00,
								0x21, 0x08,
								0x11, 0x10,
								0x09, 0x20,
								0x00, 0x00,
								0x00, 0x00,
								0x09, 0x20,
								0x11, 0x10,
								0x21, 0x08,
								0x00, 0x00,
								0x00, 0x00 };

const u8	siBadBoys00[] = {	0x00, 0x00,
								0x00, 0x00,
								0x00, 0x00,
								0x00, 0x00,
								0x00, 0x00,
								0x00, 0x00,
								0x00, 0x00,
								0x00, 0x00,
								0x00, 0x00,
								0x00, 0x00,
								0x00, 0x00,
								0x00, 0x00 };

const u8 	siBadBoys01[] = {	0x00, 0x00,
								0x00, 0x00,
								0x03, 0x80,
								0x07, 0xc0,
								0x0f, 0xe0,
								0x1b, 0xb0,
								0x1f, 0xf0,
								0x04, 0x40,
								0x0b, 0xa0,
								0x14, 0x50,
								0x00, 0x00,
								0x00, 0x00 };

const u8	siBadBoys02[] = {	0x00, 0x00,
								0x00, 0x00,
								0x03, 0x80,
								0x07, 0xc0,
								0x0f, 0xe0,
								0x1b, 0xb0,
								0x1f, 0xf0,
								0x04, 0x40,
								0x0b, 0xa0,
								0x08, 0x20,
								0x00, 0x00,
								0x00, 0x00 };


const u8 	siBadBoys11[] = {	0x00, 0x00,
								0x00, 0x00,
								0x08, 0x20,
								0x04, 0x40,
								0x0f, 0xe0,
								0x1b, 0xb0,
								0x3f, 0xf8,
								0x2f, 0xe8,
								0x28, 0x28,
								0x06, 0xc0,
								0x00, 0x00,
								0x00, 0x00 };

const u8 	siBadBoys12[] = {	0x00, 0x00,
								0x00, 0x00,
								0x08, 0x20,
								0x24, 0x48,
								0x2f, 0xe8,
								0x3b, 0xb8,
								0x3f, 0xf8,
								0x1f, 0xf0,
								0x08, 0x20,
								0x10, 0x10,
								0x00, 0x00,
								0x00, 0x00 };

const u8	siBadBoys21[] = {	0x00, 0x00,
								0x00, 0x00,
								0x07, 0xc0,
								0x1f, 0xf0,
								0x3f, 0xf8,
								0x33, 0x98,
								0x3f, 0xf8,
								0x0c, 0x60,
								0x1b, 0xb0,
								0x30, 0x18,
								0x00, 0x00,
								0x00, 0x00 };

const u8	siBadBoys22[] = {	0x00, 0x00,
								0x00, 0x00,
								0x07, 0xc0,
								0x1f, 0xf0,
								0x3f, 0xf8,
								0x33, 0x98,
								0x3f, 0xf8,
								0x0c, 0x60,
								0x1b, 0xb0,
								0x0c, 0x60,
								0x00, 0x00,
								0x00, 0x00 };

const u8	siGoodBoys[] = {	0x00, 0x18, 0x00,
								0x00, 0x18, 0x00,
								0x00, 0x3c, 0x00,
								0x00, 0xff, 0x00,
								0x0f, 0xff, 0xf0,
								0x3f, 0xff, 0xfc,
								0x3f, 0xff, 0xfc,
								0x3f, 0xff, 0xfc,
								0x3c, 0x00, 0x3c };

const u8	siGoodBoysBlk[] = {	0x00, 0x00, 0x00,
								0x00, 0x00, 0x00,
								0x00, 0x00, 0x00,
								0x00, 0x00, 0x00,
								0x00, 0x00, 0x00,
								0x00, 0x00, 0x00,
								0x00, 0x00, 0x00,
								0x00, 0x00, 0x00,
								0x00, 0x00, 0x00 };

const u8	siBadBomb00[] = {	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
								0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
const u8	siBadBomb01[] = {	0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x40,
								0x80, 0x40, 0x20, 0x40, 0x80, 0x40, 0x20 };
const u8	siBadBomb02[] = {	0x00, 0x00, 0x00, 0x20, 0x40, 0x80, 0x40,
								0x20, 0x40, 0x80, 0x40, 0x20, 0x40, 0x80 };

const u8	siGoodBomb1[] = {	0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00 };
const u8	siGoodBomb2[] = {	0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };


const u8	siDefs1[] = {		0xe0, 0xe0, 0xe0, 0xe0, 0xe0 };
const u8	siDefs2[] = {		0x00, 0x00, 0x00, 0x00, 0x00 };

void numtostr(char *buffer,int n);

const pu8	siVesselPoints[] = {
				"= 30 POINTS",
				"= 20 POINTS",
				"= 10 POINTS" };

const pu8	siPressKey = "PRESS ANY BUTTON TO START GAME";

#define CCM __attribute__ ((section (".ccmram"))) static

static SI_BADBOY	sibb[SI_MAXBADBOYS_ROWS][SI_MAXBADBOYS_COLS];
static SI_BOMB		siBomb[SI_MAXBADBOYSBOMB];

static SI_DEFENSE	sidef1[SI_MAXDEFENSES_ROWS][SI_MAXDEFENSES_COLS];
static SI_DEFENSE	sidef2[SI_MAXDEFENSES_ROWS][SI_MAXDEFENSES_COLS];
static SI_DEFENSE	sidef3[SI_MAXDEFENSES_ROWS][SI_MAXDEFENSES_COLS];
static SI_DEFENSE	sidef4[SI_MAXDEFENSES_ROWS][SI_MAXDEFENSES_COLS];

static	i16			siXGoodBoy = SI_GOODBOYSTART_X;
static	i16			siYGoodBoy = SI_GOODBOYSTART_Y;

static	i16			siGoodBoyCount;
static	i16			siGoodBoyCountOld;

static	i16			siGoodBoysKeyDelay;
static	i16			siGoodBombDelay;
static	i16			siGoodBombActive;
static	i16			siGoodBombX;
static	i16			siGoodBombY;
static	i16			siGoodBombKeyState;

static	i16			siCurrentScore;
static	i16			siBakScore;
static	i16			siBestScore;

static	i16			siBadBoysDelay;
static	i16			siBadBoysShiftX;
static	i16			siBadBoysShiftY;
static	i16			siBadBoysMode;
static	i16			siBadBoysFlip;
static	i16			siBadBoysYCount;
static	i16			siBadBoysBombDelay;
static	i16			siBadBombMoveDelay;
static	i16			siBadBoysCount;				// Count Bad Boys. If 0, you win
static	i16			siBadBoyBombOK = 1;			// 1 = fire bombs, 0 = No

static	u8			siScore[24];
static	float 		AccBuffer[3] = {0.0f};


//#undef static

u8	siAnyButtonPressed(void) {

u32		b;

	b = GPIOA->IDR;
	return (b&SI_FIRE_BUTTON);
	if ((b & 0x00000001) != (SI_FIRE_BUTTON/* | SI_LEFT_BUTTON | SI_RIGHT_BUTTON*/)) return(1);
	return(0);
}

void siYouWin(void) {

	vidClearScreen();
	gdiRectangle(0,0,(VID_PIXELS_X - 1),VID_VSIZE - 1,0);

	gdiDrawTextEx(167,80,"* YOU WIN *",GDI_ROP_XOR);
	while(1) {
		if (siAnyButtonPressed()) return;
		gdiDrawTextEx(108,170,siPressKey,GDI_ROP_XOR);
		sysDelayMs(400);
		if (siAnyButtonPressed()) return;
		gdiDrawTextEx(108,170,siPressKey,GDI_ROP_XOR);
		if (siAnyButtonPressed()) return;
		sysDelayMs(200);
	};
}

void siYouLose(void) {

	vidClearScreen();
	gdiRectangle(0,0,(VID_PIXELS_X - 1),VID_VSIZE - 1,0);

	gdiDrawTextEx(164,80,"* YOU LOSE *",GDI_ROP_XOR);
	while(1) {
		if (siAnyButtonPressed()) return;
		gdiDrawTextEx(108,170,siPressKey,GDI_ROP_XOR);
		sysDelayMs(400);
		if (siAnyButtonPressed()) return;
		gdiDrawTextEx(108,170,siPressKey,GDI_ROP_XOR);
		if (siAnyButtonPressed()) return;
		sysDelayMs(200);
	};

}

char * strcpy(char *dest, char *src) {
	while(*dest++=*src++);
	return dest;
}

int strlen(const char *str)
{
        const char *s;
        for (s = str; *s; ++s)
                ;
        return (s - str);
}

void siInitialScreen(void) {

u16		i, x, y, l, j;
pu8		ptr = NULL;
u8		buf[] = " ";

	vidClearScreen();

	gdiRectangle(0,0,(VID_PIXELS_X - 1),VID_VSIZE - 1,0);

	gdiDrawTextEx(180, 40, "ARTEKIT", GDI_ROP_COPY);
	gdiDrawTextEx(156, 55, "SPACE INVADERS", GDI_ROP_COPY);
	gdiDrawTextEx(180, 70, "LEVEL I", GDI_ROP_COPY);

	sysDelayMs(1000);

	gdiDrawTextEx(130,110,"* SCORE ADVANCE TABLE *",GDI_ROP_XOR);
	sysDelayMs(400);
	y = 125;
	for (i = 0; i < 3; i++) {
		x = 155;
		switch(i) {
			case 0:		ptr = (pu8) siBadBoys01;
						break;
			case 1:		ptr = (pu8) siBadBoys11;
						break;
			case 2:		ptr = (pu8) siBadBoys21;
						break;
		}
		gdiBitBlt(NULL,x,y,15,12,ptr,GDI_ROP_COPY);
		x += 20;
		l = strlen((const char*)siVesselPoints[i]);
		ptr = siVesselPoints[i];
		for (j = 0; j < l; j++) {
			sysDelayMs(25);
			buf[0] = *ptr++;
			gdiDrawTextEx(x,y + 2,buf,GDI_ROP_COPY);
			x += 6;
		}
		y += 12;
		sysDelayMs(300);
	}
	while(1) {
		if (siAnyButtonPressed()) return;
		gdiDrawTextEx(108,170,siPressKey,GDI_ROP_XOR);
		sysDelayMs(400);
		if (siAnyButtonPressed()) return;
		gdiDrawTextEx(108,170,siPressKey,GDI_ROP_XOR);
		if (siAnyButtonPressed()) return;
		sysDelayMs(200);

	};

}
int leftcol, rtcol, count, shiftdown=0;

CCM void siShiftBadboys(void) {

	if(shiftdown>0) {
		siBadBoysShiftY += 2;
		shiftdown--;
	}  else {
	if (!siBadBoysMode) {
		if (++siBadBoysShiftX+rtcol*20 >= 288) {
			siBadBoysMode = 1;
			siBadBoysShiftX -= 2;
			siBadBoysShiftY += 2;
			shiftdown=8;
			if (siBadBoysYCount < 459) siBadBoysYCount += SI_BADBOYSSPEEDCOUNT;
		} else {
			siBadBoysShiftX += 1;
		}
	} else {
		if ( --siBadBoysShiftX+leftcol*20 < -10) {
			siBadBoysMode = 0;
			siBadBoysShiftX += 2;
			siBadBoysShiftY += 2;
			shiftdown=8;
			if (siBadBoysYCount < 459) siBadBoysYCount += SI_BADBOYSSPEEDCOUNT;
		} else {
			siBadBoysShiftX -= 1;
		}
	}
	}

	(siBadBoysFlip == 0) ? (siBadBoysFlip = 1) : (siBadBoysFlip = 0);
}


CCM void siDrawBadboys(void) {

u16		i, n;

	if (--siBadBoysDelay > 0) return;
	siBadBoysDelay = SI_BADBOYSSTARTDELAY - siBadBoysYCount;
	leftcol=110;rtcol=0;count=0;
	for (i = 0; i < SI_MAXBADBOYS_ROWS; i++) {
		for (n = 0; n < SI_MAXBADBOYS_COLS; n++) {
			if (sibb[i][n].mode == SI_ALIVE) {
				count++;
				if(n<leftcol)
					leftcol=n;
				if(n>rtcol)
					rtcol=n;
				if (!siBadBoysFlip) {
					gdiBitBlt(NULL,sibb[i][n].x + siBadBoysShiftX,sibb[i][n].y + siBadBoysShiftY,15,12,sibb[i][n].b1,GDI_ROP_COPY);
				} else {
					gdiBitBlt(NULL,sibb[i][n].x + siBadBoysShiftX,sibb[i][n].y + siBadBoysShiftY,15,12,sibb[i][n].b2,GDI_ROP_COPY);
				}
			} else {
				if (sibb[i][n].mode == SI_DESTROYED) {
					sibb[i][n].mode = SI_CANCEL;
					gdiBitBlt(NULL,sibb[i][n].x + siBadBoysShiftX,sibb[i][n].y + siBadBoysShiftY,15,12,(pu8) siBadBoys99,GDI_ROP_COPY);
				} else {
					if (sibb[i][n].mode == SI_CANCEL) {
						sibb[i][n].mode = SI_DEAD;
						gdiBitBlt(NULL,sibb[i][n].x + siBadBoysShiftX,sibb[i][n].y + siBadBoysShiftY,15,12,(pu8) siBadBoys00,GDI_ROP_COPY);
					}
				}
			}
		}
	}
	siShiftBadboys();
	siBadBoysDelay = count*10;
}

CCM void siShowDefenses(void) {

u16		i, j, n;

	for (i = 0; i < 4; i++) {
		for (j = 0; j < SI_MAXDEFENSES_ROWS; j++) {
			for (n = 0; n < SI_MAXDEFENSES_COLS; n++) {
				switch(i) {
					case 0:		if (sidef1[j][n].mode == SI_ALIVE) {
									gdiBitBlt(NULL,sidef1[j][n].x,sidef1[j][n].y,3,5,(pu8) siDefs1,GDI_ROP_COPY);
								} else {
									gdiBitBlt(NULL,sidef1[j][n].x,sidef1[j][n].y,3,5,(pu8) siDefs2,GDI_ROP_COPY);
								}
								break;
					case 1:		if (sidef2[j][n].mode == SI_ALIVE) {
									gdiBitBlt(NULL,sidef2[j][n].x,sidef2[j][n].y,3,5,(pu8) siDefs1,GDI_ROP_COPY);
								} else {
									gdiBitBlt(NULL,sidef2[j][n].x,sidef2[j][n].y,3,5,(pu8) siDefs2,GDI_ROP_COPY);
								}
								break;
					case 2:		if (sidef3[j][n].mode == SI_ALIVE) {
									gdiBitBlt(NULL,sidef3[j][n].x,sidef3[j][n].y,3,5,(pu8) siDefs1,GDI_ROP_COPY);
								} else {
									gdiBitBlt(NULL,sidef3[j][n].x,sidef3[j][n].y,3,5,(pu8) siDefs2,GDI_ROP_COPY);
								}
								break;
					case 3:		if (sidef4[j][n].mode == SI_ALIVE) {
									gdiBitBlt(NULL,sidef4[j][n].x,sidef4[j][n].y,3,5,(pu8) siDefs1,GDI_ROP_COPY);
								} else {
									gdiBitBlt(NULL,sidef4[j][n].x,sidef4[j][n].y,3,5,(pu8) siDefs2,GDI_ROP_COPY);
								}
								break;


				}
			}
		}
	}
}
CCM void siMoveGoodBoys(void) {

	if (--siGoodBoysKeyDelay > 0) return;
	siGoodBoysKeyDelay = SI_GOODBOYSKEYDELAY;
	Demo_CompassReadAcc(AccBuffer);
	int x=(int)AccBuffer[0];
	int y=(int)AccBuffer[1];
	int z=(int)AccBuffer[2];

/*
	numtostr(siScore,x);
	gdiDrawTextEx(340,20,siScore,GDI_ROP_COPY);
        numtostr(siScore,y);
        gdiDrawTextEx(340,40,siScore,GDI_ROP_COPY);
        numtostr(siScore,z);
        gdiDrawTextEx(340,60,siScore,GDI_ROP_COPY);
*/

//	if ((GPIOA->IDR & SI_LEFT_BUTTON) == 0) {
	if (y<-100) {
		if (siXGoodBoy > 8) {
			siXGoodBoy -= 2;
			gdiBitBlt(NULL,siXGoodBoy,siYGoodBoy,24,9,(pu8) siGoodBoys,GDI_ROP_COPY);
		}
	}
//	if ((GPIOA->IDR & SI_RIGHT_BUTTON) == 0) {
	if (y>100) {
		if (siXGoodBoy < 290) {
			siXGoodBoy += 2;
			gdiBitBlt(NULL,siXGoodBoy,siYGoodBoy,24,9,(pu8) siGoodBoys,GDI_ROP_COPY);
		}
	}


}

CCM void siMoveGoodBomb(void) {

i16		d, i, n;

	if (!siGoodBombActive) return;
	if (--siGoodBombDelay > 0) return;
	siGoodBombDelay = SI_GOODBOMBDELAY;

	gdiBitBlt(NULL,siGoodBombX,siGoodBombY,2,6,(pu8) siGoodBomb1,GDI_ROP_COPY);

//	Test if bomb touch defenses

	for (d = 0; d < 4; d++) {
		for (i = 0; i < SI_MAXDEFENSES_ROWS; i++) {
			for (n = 0; n < SI_MAXDEFENSES_COLS; n++) {
				switch(d) {
					case 0:		if (sidef1[i][n].mode == SI_ALIVE) {
									if (siGoodBombX >= sidef1[i][n].x && siGoodBombX <= (sidef1[i][n].x + 3)) {
										if (siGoodBombY <= (sidef1[i][n].y + 5) && siGoodBombY >= sidef1[i][n].y) {
											sidef1[i][n].mode = SI_DEAD;
											gdiBitBlt(NULL,sidef1[i][n].x,sidef1[i][n].y,3,5,(pu8) siDefs2,GDI_ROP_COPY);
											gdiBitBlt(NULL,siGoodBombX,siGoodBombY,2,6,(pu8) siGoodBomb2,GDI_ROP_COPY);
											siGoodBombActive = 0;
//											siShowDefenses();
											return;
										}
									}
								}
								break;
					case 1:		if (sidef2[i][n].mode == SI_ALIVE) {
									if (siGoodBombX >= sidef2[i][n].x && siGoodBombX <= (sidef2[i][n].x + 3)) {
										if (siGoodBombY <= (sidef2[i][n].y + 5) && siGoodBombY >= sidef2[i][n].y) {
											sidef2[i][n].mode = SI_DEAD;
											gdiBitBlt(NULL,sidef2[i][n].x,sidef2[i][n].y,3,5,(pu8) siDefs2,GDI_ROP_COPY);
											gdiBitBlt(NULL,siGoodBombX,siGoodBombY,2,6,(pu8) siGoodBomb2,GDI_ROP_COPY);
											siGoodBombActive = 0;
//											siShowDefenses();
											return;
										}
									}
								}
								break;
					case 2:		if (sidef3[i][n].mode == SI_ALIVE) {
									if (siGoodBombX >= sidef3[i][n].x && siGoodBombX <= (sidef3[i][n].x + 3)) {
										if (siGoodBombY <= (sidef3[i][n].y + 5) && siGoodBombY >= sidef3[i][n].y) {
											sidef3[i][n].mode = SI_DEAD;
											gdiBitBlt(NULL,sidef3[i][n].x,sidef3[i][n].y,3,5,(pu8) siDefs2,GDI_ROP_COPY);
											gdiBitBlt(NULL,siGoodBombX,siGoodBombY,2,6,(pu8) siGoodBomb2,GDI_ROP_COPY);
											siGoodBombActive = 0;
//											siShowDefenses();
											return;
										}
									}
								}
								break;
					case 3:		if (sidef4[i][n].mode == SI_ALIVE) {
									if (siGoodBombX >= sidef4[i][n].x && siGoodBombX <= (sidef4[i][n].x + 3)) {
										if (siGoodBombY <= (sidef4[i][n].y + 5) && siGoodBombY >= sidef4[i][n].y) {
											sidef4[i][n].mode = SI_DEAD;
											gdiBitBlt(NULL,sidef4[i][n].x,sidef4[i][n].y,3,5,(pu8) siDefs2,GDI_ROP_COPY);
											gdiBitBlt(NULL,siGoodBombX,siGoodBombY,2,6,(pu8) siGoodBomb2,GDI_ROP_COPY);
											siGoodBombActive = 0;
//											siShowDefenses();
											return;
										}
									}
								}
								break;

				}
			}
		}
	}

//	Test if bomb touch any Bad Boy

	for (i = 0; i < SI_MAXBADBOYS_ROWS; i++) {
		for (n = 0; n < SI_MAXBADBOYS_COLS; n++) {
			if (sibb[i][n].mode == SI_ALIVE) {
				if (siGoodBombX >= (sibb[i][n].x + siBadBoysShiftX) && siGoodBombX <= (sibb[i][n].x + siBadBoysShiftX + 15)) {
					if (siGoodBombY <= (sibb[i][n].y + siBadBoysShiftY + 12) && siGoodBombY >= (sibb[i][n].y + siBadBoysShiftY)) {
						sibb[i][n].mode = SI_DESTROYED;
//						gdiBitBlt(NULL,sibb[i][n].x + siBadBoysShiftX,sibb[i][n].y + siBadBoysShiftY,15,12,(pu8) siBadBoys99,GDI_ROP_COPY);
						gdiBitBlt(NULL,siGoodBombX,siGoodBombY,2,6,(pu8) siGoodBomb2,GDI_ROP_COPY);
						siGoodBombActive = 0;
						--siBadBoysCount;
						switch(i) {
							case 0:		siCurrentScore += 30;	break;
							case 1:		siCurrentScore += 20;	break;
							case 2:		siCurrentScore += 20;	break;
							case 3:		siCurrentScore += 10;	break;
						}
						return;
					}
				}
			}
		}
	}


	if (siGoodBombY < 5) {
		gdiBitBlt(NULL,siGoodBombX,siGoodBombY,2,6,(pu8) siGoodBomb2,GDI_ROP_COPY);
		siGoodBombActive = 0;
	} else {
		siGoodBombY -= 3;
	}
}

void siGoodBombStart(void) {

	if ((GPIOA->IDR & SI_FIRE_BUTTON) == 0) {
		if (siGoodBombKeyState == 0 && siGoodBombActive == 0) {
			siGoodBombX = siXGoodBoy + SI_GOODBOYSHOTPOINT;
			siGoodBombY = SI_GOODBOYSTART_Y - 6;
			siGoodBombActive = 1;
			siGoodBombKeyState = 1;
		}
	} else {
		siGoodBombKeyState = 0;
	}

}

CCM void siBadBoysFire(void) {

i16		i, r, col = 0, row = 0,x;

	if (siBadBoyBombOK == 0) return;		// Bomb disabled

	if (--siBadBoysBombDelay != 0) return;
	siBadBoysBombDelay = SI_BADBOYSBOMBDELAY;

	srand(sysTicks);
	r = rand();
	if ((r & 0x03) == 0x01) {			// Fire bomb

//	Select a random Bad Boy to fire bomb
// Select a random Bad Boy to fire bomb
	for(x=0;x<20;x++) {
		col = rand() % SI_MAXBADBOYS_COLS;
		for (row = (SI_MAXBADBOYS_ROWS - 1); row >= 0; row--) {
			if (sibb[row][col].mode == SI_ALIVE){
				for (i = 0; i < SI_MAXBADBOYSBOMB; i++) {
					if (siBomb[i].mode == SI_DEAD) {
						siBomb[i].x = sibb[row][col].x + 7 + siBadBoysShiftX;
						siBomb[i].y = sibb[row][col].y + 12 + siBadBoysShiftY;
						siBomb[i].mode = SI_ALIVE;
						return;
					}
				}
			}
		}
	}
/*
		while(1) {
			col = rand() % SI_MAXBADBOYS_COLS;
			for (row = (SI_MAXBADBOYS_ROWS - 1); row >= 0; row--) {
				if (sibb[row][col].mode == SI_ALIVE) {
					for (i = 0; i < SI_MAXBADBOYSBOMB; i++) {
						if (siBomb[i].mode == SI_DEAD) {
							siBomb[i].x = sibb[row][col].x + 7 + siBadBoysShiftX;
							siBomb[i].y = sibb[row][col].y + 12 + siBadBoysShiftY;
							siBomb[i].mode = SI_ALIVE;
							return;
						}
					}
				}
			}
		}
*/
	}

}

CCM i16 siDrawBadBoyBomb(void) {

i16		i, v, d, n;
i16		ret = 0;

	siBadBoysFire();

	if (--siBadBombMoveDelay != 0) return(ret);;
	siBadBombMoveDelay = SI_BADBOMBMOVEDELAY;

	for (v = 0; v < SI_MAXBADBOYSBOMB; v++) {
		if (siBomb[v].mode == SI_ALIVE) {
			if (siBomb[v].flip == 0) {
				gdiBitBlt(NULL,siBomb[v].x,siBomb[v].y,3,14,(pu8) siBadBomb01,GDI_ROP_COPY);
				siBomb[v].flip = 1;
			} else {
				gdiBitBlt(NULL,siBomb[v].x,siBomb[v].y,3,14,(pu8) siBadBomb02,GDI_ROP_COPY);
				siBomb[v].flip = 0;
			}

//	See if Bad Boys bomb touch defenses

			for (d = 0; d < 4; d++) {
				for (i = 0; i < SI_MAXDEFENSES_ROWS; i++) {
					for (n = 0; n < SI_MAXDEFENSES_COLS; n++) {
						switch(d) {
							case 0:		if (sidef1[i][n].mode == SI_ALIVE) {
											if (siBomb[v].x >= sidef1[i][n].x && siBomb[v].x <= (sidef1[i][n].x + 3)) {
												if ((siBomb[v].y + 12) >= sidef1[i][n].y && (siBomb[v].y + 12) <= (sidef1[i][n].y + 5)) {
													sidef1[i][n].mode = SI_DEAD;
													gdiBitBlt(NULL,sidef1[i][n].x,sidef1[i][n].y,3,5,(pu8) siDefs2,GDI_ROP_COPY);
													gdiBitBlt(NULL,siBomb[v].x,siBomb[v].y,3,14,(pu8) siBadBomb00,GDI_ROP_COPY);
													siBomb[v].mode = SI_DEAD;
												}
											}
										}
										break;
							case 1:		if (sidef2[i][n].mode == SI_ALIVE) {
											if (siBomb[v].x >= sidef2[i][n].x && siBomb[v].x <= (sidef2[i][n].x + 3)) {
												if ((siBomb[v].y + 12) >= sidef2[i][n].y && (siBomb[v].y + 12) <= (sidef2[i][n].y + 5)) {
													sidef2[i][n].mode = SI_DEAD;
													gdiBitBlt(NULL,sidef2[i][n].x,sidef2[i][n].y,3,5,(pu8) siDefs2,GDI_ROP_COPY);
													gdiBitBlt(NULL,siBomb[v].x,siBomb[v].y,3,14,(pu8) siBadBomb00,GDI_ROP_COPY);
													siBomb[v].mode = SI_DEAD;
												}
											}
										}
										break;
							case 2:		if (sidef3[i][n].mode == SI_ALIVE) {
											if (siBomb[v].x >= sidef3[i][n].x && siBomb[v].x <= (sidef3[i][n].x + 3)) {
												if ((siBomb[v].y + 12) >= sidef3[i][n].y && (siBomb[v].y + 12) <= (sidef3[i][n].y + 5)) {
													sidef3[i][n].mode = SI_DEAD;
													gdiBitBlt(NULL,sidef3[i][n].x,sidef3[i][n].y,3,5,(pu8) siDefs2,GDI_ROP_COPY);
													gdiBitBlt(NULL,siBomb[v].x,siBomb[v].y,3,14,(pu8) siBadBomb00,GDI_ROP_COPY);
													siBomb[v].mode = SI_DEAD;
												}
											}
										}
										break;
							case 3:		if (sidef4[i][n].mode == SI_ALIVE) {
											if (siBomb[v].x >= sidef4[i][n].x && siBomb[v].x <= (sidef4[i][n].x + 3)) {
												if ((siBomb[v].y + 12) >= sidef4[i][n].y && (siBomb[v].y + 12) <= (sidef4[i][n].y + 5)) {
													sidef4[i][n].mode = SI_DEAD;
													gdiBitBlt(NULL,sidef4[i][n].x,sidef4[i][n].y,3,5,(pu8) siDefs2,GDI_ROP_COPY);
													gdiBitBlt(NULL,siBomb[v].x,siBomb[v].y,3,14,(pu8) siBadBomb00,GDI_ROP_COPY);
													siBomb[v].mode = SI_DEAD;
												}
											}
										}
										break;
						}
					}
				}
			}

//	See if Bad Boys bomb touch Good Boy

			if (siBomb[v].x >= siXGoodBoy && siBomb[v].x <= (siXGoodBoy + 24)) {
				if ((siBomb[v].y + 12) >= siYGoodBoy && (siBomb[v].y + 12) <= (siYGoodBoy + 9)) {
					gdiBitBlt(NULL,siBomb[v].x,siBomb[v].y,3,14,(pu8) siBadBomb00,GDI_ROP_COPY);
					gdiBitBlt(NULL,siXGoodBoy,SI_GOODBOYSTART_Y,24,9,(pu8) siGoodBoysBlk,GDI_ROP_COPY);
					ret = 1;	// Good Boy was killed
				}
			}

//	Touch nothing, go ahead

			if (siBomb[v].mode != SI_DEAD) {
				siBomb[v].y += 3;
				if (siBomb[v].y >= (VID_PIXELS_Y - 16)) {
					gdiBitBlt(NULL,siBomb[v].x,siBomb[v].y - 3,3,14,(pu8) siBadBomb00,GDI_ROP_COPY);
					siBomb[v].mode = SI_DEAD;
				}
			}
		}
	}
	return(ret);
}

void siCancelAllBadBoms(void) {

i16		i;

	for (i = 0; i < SI_MAXBADBOYSBOMB; i++) {
		if (siBomb[i].mode != SI_DEAD) {
			gdiBitBlt(NULL,siBomb[i].x,siBomb[i].y - 3,3,14,(pu8) siBadBomb00,GDI_ROP_COPY);
			siBomb[i].mode = SI_DEAD;
		}
	}
}

void numtostr(char *buffer,int n) {
int i = 0;
int isNeg = n<0;
unsigned int n1 = isNeg ? -n : n;
int t;

while(n1!=0)
{
    buffer[i++] = n1%10+'0';
    n1=n1/10;
}

if(isNeg)
    buffer[i++] = '-';

buffer[i] = '\0';

for(t = 0; t < i/2; t++)
{
    buffer[t] ^= buffer[i-t-1];
    buffer[i-t-1] ^= buffer[t];
    buffer[t] ^= buffer[i-t-1];
}

if(n == 0)
{
    buffer[0] = '0';
    buffer[1] = '\0';
}
}

CCM void siDrawGoodBoyLeft(void) {

i16		i, x, t;

	if (siGoodBoyCount != siGoodBoyCountOld) {
		strcpy((char*) siScore,"LEFT: ");
		numtostr(siScore+6,siGoodBoyCount - 1);
//		sprintf((char*) siScore,"LEFT: %d",siGoodBoyCount - 1);
		gdiDrawTextEx(340,170,siScore,GDI_ROP_COPY);

		siGoodBoyCountOld = siGoodBoyCount;
		for (t = 0; t < 4; t++) {
			x = 322;
			for (i = 1; i < SI_MAXGOODBOYS; i++) {
				gdiBitBlt(NULL,x,SI_GOODBOYSTART_Y,24,9,(pu8) siGoodBoysBlk,GDI_ROP_COPY);
				x += 24;
			}
			sysDelayMs(200);
			x = 322;
			for (i = 1; i < SI_MAXGOODBOYS; i++) {
				if (i < siGoodBoyCount) {
					gdiBitBlt(NULL,x,SI_GOODBOYSTART_Y,24,9,(pu8) siGoodBoys,GDI_ROP_COPY);
				} else {
					gdiBitBlt(NULL,x,SI_GOODBOYSTART_Y,24,9,(pu8) siGoodBoysBlk,GDI_ROP_COPY);
				}
				x += 24;
			}
			sysDelayMs(300);
		}
		siXGoodBoy = SI_GOODBOYSTART_X;
		gdiBitBlt(NULL,siXGoodBoy,siYGoodBoy,24,9,(pu8) siGoodBoys,GDI_ROP_COPY);
	}
}

//	Test if Bad Boys are closed to defenses. 0 = No, 1 = Game Over

i16 siBadBoysClosed(void) {

int		i, n;

	for (i = (SI_MAXBADBOYS_ROWS - 1); i >= 0; i--) {
		for (n = 0; n < SI_MAXBADBOYS_COLS; n++) {
			if (sibb[i][n].mode == SI_ALIVE) {
				if (sibb[i][n].y + siBadBoysShiftY + 12 >= SI_DEFSSTARTY) {
					return(1);
				} else {
					return(0);
				}
			}
		}
	}
	return(0);
}

//	The game

void siTheGame(void) {

	while(1) {

		sysDelayMs(1);

		siDrawGoodBoyLeft();
		siMoveGoodBoys();
		siGoodBombStart();
		siMoveGoodBomb();
		if (siBadBoysClosed() == 1) {
			siYouLose();
			return;
		}
		if (siBadBoysCount > 0) {
			if (siDrawBadBoyBomb()) {			// Good Boy was killed
				if (--siGoodBoyCount == 0) {	// Game over
					siYouLose();
					return;
				} else {
					siCancelAllBadBoms();
					gdiBitBlt(NULL,siXGoodBoy,siYGoodBoy,24,9,(pu8) siGoodBoysBlk,GDI_ROP_COPY);
				}
			}
		} else {
			siYouWin();
			return;
		}
		siDrawBadboys();
		if (siBakScore != siCurrentScore) {
			siBakScore = siCurrentScore;
			strcpy((char*) siScore,"SCORE: ");
                	numtostr(siScore+7,siCurrentScore);

	//		sprintf((char*) siScore,"SCORE: %04d",siCurrentScore);
			gdiDrawTextEx(328,20,siScore,GDI_ROP_COPY);
			//sprintf((char*) siScore,"BEST:  %04d",siBestScore);
			strcpy((char*) siScore,"BEST: ");
			numtostr(siScore+6,siBestScore);
			gdiDrawTextEx(328,29,siScore,GDI_ROP_COPY);

		}
	}
}

//*****************************************************************************
//	Function siInit
//
//	Init Space Invaders
//
//	return			none
//*****************************************************************************
void siInit(void) {

GPIO_InitTypeDef	GPIO_InitStructure;
u16					i, n, j, x, y;

//	Configure button pins

	GPIO_InitStructure.GPIO_Pin = SI_FIRE_BUTTON | SI_LEFT_BUTTON | SI_RIGHT_BUTTON;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	gdiBitBlt(NULL,0,0,(VID_PIXELS_X - 1),232,(pu8) siLogo,0);
	sysDelayMs(5000);

	Demo_CompassConfig();

start:

	siInitialScreen();

	vidClearScreen();
	gdiRectangle(0,0,(VID_PIXELS_X - 1),VID_VSIZE - 1,0);
	gdiLine(NULL,320,0,320,VID_VSIZE,GDI_ROP_COPY);

//	Preload Bad Boys
	siBadBoysShiftY=0;
	siBadBoysShiftX=0;

	for (i = 0; i < SI_MAXBADBOYS_ROWS; i++) {
		x = 15;
		y = SI_BADBOYS_START_Y + ((SI_MAXBADBOYS_ROWS + 12) * i);
		for (n = 0; n < SI_MAXBADBOYS_COLS; n++) {
			sibb[i][n].x = x;
			sibb[i][n].y = y;
			sibb[i][n].mode = SI_ALIVE;
			sibb[i][n].flip = 0;
			if (i == 0) {
				sibb[i][n].b1 = (pu8) siBadBoys01;
				sibb[i][n].b2 = (pu8) siBadBoys02;
			}
			if (i == 1 || i == 2) {
				sibb[i][n].b1 = (pu8) siBadBoys11;
				sibb[i][n].b2 = (pu8) siBadBoys12;
			}
			if (i >= 3) {
				sibb[i][n].b1 = (pu8) siBadBoys21;
				sibb[i][n].b2 = (pu8) siBadBoys22;
			}
			x += 20;
		}
	}

//	Preload defenses

	for (i = 0; i < 4; i++) {
		y = SI_DEFSSTARTY;
		for (j = 0; j < SI_MAXDEFENSES_ROWS; j++) {
			x = SI_DEFSSTARTX +  (i * SI_DEFXSEPARATOR);;
			for (n = 0; n < SI_MAXDEFENSES_COLS; n++) {
			switch(i) {
				case 0:		if (j == 0 || j == 1) {
								sidef1[j][n].x = x;
								sidef1[j][n].y = y;
								sidef1[j][n].mode = SI_ALIVE;
							} else {
								if (n == 0 || n == (SI_MAXDEFENSES_COLS - 1)) {
									sidef1[j][n].x = x;
									sidef1[j][n].y = y;
									sidef1[j][n].mode = SI_ALIVE;
								} else {
									sidef1[j][n].x = x;
									sidef1[j][n].y = y;
									sidef1[j][n].mode = SI_DEAD;
								}
							}
							x += 3;
							break;
				case 1:		if (j == 0 || j == 1) {
								sidef2[j][n].x = x;
								sidef2[j][n].y = y;
								sidef2[j][n].mode = SI_ALIVE;
							} else {
								if (n == 0 || n == (SI_MAXDEFENSES_COLS - 1)) {
									sidef2[j][n].x = x;
									sidef2[j][n].y = y;
									sidef2[j][n].mode = SI_ALIVE;
								} else {
									sidef2[j][n].x = x;
									sidef2[j][n].y = y;
									sidef2[j][n].mode = SI_DEAD;
								}
							}
							x += 3;
							break;
				case 2:		if (j == 0 || j == 1) {
								sidef3[j][n].x = x;
								sidef3[j][n].y = y;
								sidef3[j][n].mode = SI_ALIVE;
							} else {
								if (n == 0 || n == (SI_MAXDEFENSES_COLS - 1)) {
									sidef3[j][n].x = x;
									sidef3[j][n].y = y;
									sidef3[j][n].mode = SI_ALIVE;
								} else {
									sidef3[j][n].x = x;
									sidef3[j][n].y = y;
									sidef3[j][n].mode = SI_DEAD;
								}
							}
							x += 3;
							break;
				case 3:		if (j == 0 || j == 1) {
								sidef4[j][n].x = x;
								sidef4[j][n].y = y;
								sidef4[j][n].mode = SI_ALIVE;
							} else {
								if (n == 0 || n == (SI_MAXDEFENSES_COLS - 1)) {
									sidef4[j][n].x = x;
									sidef4[j][n].y = y;
									sidef4[j][n].mode = SI_ALIVE;
								} else {
									sidef4[j][n].x = x;
									sidef4[j][n].y = y;
									sidef4[j][n].mode = SI_DEAD;
								}
							}
							x += 3;
							break;
				}
			}
			y += 5;
		}
	}

//	Init default variables

	siXGoodBoy = SI_GOODBOYSTART_X;
	siYGoodBoy = SI_GOODBOYSTART_Y;

	siBadBoysDelay = SI_BADBOYSSTARTDELAY;
	siBadBoysShiftX = 0;
	siBadBoysShiftX = 0;
	siBadBoysMode = 0;
	siBadBoysFlip = 0;
	siBadBoysYCount = 0;
	siGoodBoysKeyDelay = SI_GOODBOYSKEYDELAY;
	siGoodBombDelay = SI_GOODBOMBDELAY;
	if (siCurrentScore > siBestScore) siBestScore = siCurrentScore;
	siCurrentScore = 0;
	siBadBoysBombDelay = SI_BADBOYSBOMBDELAY;
	siBadBombMoveDelay = SI_BADBOMBMOVEDELAY;
	siBadBoysCount = SI_MAXBADBOYS_COLS * SI_MAXBADBOYS_ROWS;
	siBakScore = -1;
	siGoodBoyCount = SI_MAXGOODBOYS;
	siGoodBoyCountOld = 0;

//	Show Good Boy first time

	gdiBitBlt(NULL,siXGoodBoy,siYGoodBoy,24,9,(pu8) siGoodBoys,GDI_ROP_COPY);

//	Show Bad Boys first time

	siDrawBadboys();

//	Show defenses first time

	siShowDefenses();

//	Start Gane

	siTheGame();
	goto start;
}