#include "../plugin.h"

#define DEFAULTHUDNAME "ftehud.hud"

#define MAX_ELEMENTS 128

int testvar;
int testvar2;
int testvar3;
int testvar4;
int K_UPARROW;
int K_DOWNARROW;
int K_LEFTARROW;
int K_RIGHTARROW;
int K_ESCAPE;
int K_MOUSE1;
int K_MOUSE2;
int K_HOME;
int K_SHIFT;
int K_SPACE;
int K_F1;
int K_F2;


#define texture qhandle_t
#define bool qboolean

float realtime;

#define Sound_Start(x)






void vecNorm(float *in, float *out)
{	
	float	new;	

	new = in[0] * in[0] + in[1] * in[1] + in[2]*in[2];
	new = (float)sqrt(new);
	
	if (new == 0)
		out[0] = out[1] = out[2] = 0;
	else
	{
		new = 1/new;
		out[0] = in[0] * new;
		out[1] = in[1] * new;
		out[2] = in[2] * new;
	}
	
}

#if 0
#define MAXCANNONS 4
#define MAXBULLETS 256
#define MAXMONSTERS 256
#define ENEMYTYPES 10
#define SHOTLEVELS 10
#else
enum {
	M_CANNON1,
	M_CANNON2,
	M_CANNON3,
	M_CANNON4,
	M_CANNON5,
	M_CANNON6,
	M_CANNON7,
	M_CANNON8,
	M_CANNON9,
	M_CANNON10,
	M_CANNON11,
	M_CANNON12,

	M_ROCKETL1 = 50,
	M_ROCKETL2,
	M_ROCKETL3,
	M_ROCKETL4,
	M_ROCKETL5,
	M_ROCKETL6,
	M_ROCKETL7,
	M_ROCKETL8,
	M_ROCKETL9,
	M_ROCKETL10,
	M_ROCKETL11,
	M_ROCKETL12,

	M_FORWARD = 100,
	M_DIAG,
	M_DIAG2,
	M_SIDE,

	MAXADDONS
};
#define FIRSTCANNON M_CANNON1
#define LASTCANNON M_ROCKETL1-1

#define FIRSTROCKET M_ROCKETL1
#define LASTROCKET M_FORWARD-1

#define FIRSTCENTRALMOD M_FORWARD
#define LASTCENTRALMOD MAXADDONS-1

int MAXBULLETS = 255;
int MAXMONSTERS = 256;
int MAXSQUADS = 256;
int MAXROUTES = 64;
int MAXROUTEPOINTS=10;
#define ENEMYTYPES monsterpics
#define SHOTLEVELS weaponlevels
#endif
#define CONT_LEFTKEY	1
#define CONT_RIGHTKEY	2
#define CONT_FIREKEY	4
#define CONT_UPKEY		8
#define CONT_DOWNKEY	16
#define CONT_MOUSE		32	//right mouse button pressed

#define PLAYERSHIPSPEEDX	2
#define PLAYERSHIPSPEEDY	2
#define ENEMYSHIPSPEEDX	(random()-0.5)
#define ENEMYSHIPSPEEDY	(random()*2+(float)1)


#define PUP_SHRUNKEN	1	//one round only

void SIRestartGame (void);
float random(void);

int SIlevel;
char SILevelName[128];

int weaponlevels;
int monsterpics;

//Textures in structures are pointers to the texture number. This means we don't have to cycle through each one when we reload the textures.

typedef struct SIEnemyType_s
{
	texture *picture;
	float width;
	float height;
	int health;

	float FireProb;

	int reward;

	int number;

	int AI;
	int healthregen;

	int shotdamage;
	texture *shotpicture;
} SIEnemyType_t;

typedef struct SIRoute_s
{
	int numpoints;
	vec3_t pos[1];
} SIRoute_t;

typedef struct SISquad_s
{
	int route;
	int type;
	int number;
	float interval;
	float time;
	float speed;
} SISquad_t;


typedef struct SIaddon_s
{
	float xoff;
	float yoff;

	int power;
	float refire;
	float reloadtime;
	texture *tex;
} SIaddon_t;

typedef struct SIp_s
{
	float x;
	float y;
	float width;
	float height;
	int cash;
	int health;	

	int contols;
	int powerups;	
		
	SIaddon_t cannon[MAXADDONS];
} SIp_t;

typedef struct SImonster_s
{
	float xpos;
	float ypos;
	float width;
	float height;

	int routenum;
	int destnum;

	float xvel;
	float yvel;

	int health;

	int timetoregen;

	SIEnemyType_t *EnemyType;
} SImonster_t;

typedef struct SIbullet_s
{
	int type;
	int charge;

	float xpos;
	float ypos;
	float width;
	float height;
	float xvel;
	float yvel;
	float yaccel;

	qboolean inuse;
	int damage;
	float alpha;
	float alphachange;

	texture *tex;
} SIbullet_t;

typedef struct ShopRegion_s
{
	float x;
	float y;
	float width;
	float height;

	char *text;

	texture *tex;
	qboolean (*AppearCondition) (int ident);
	void (*CallFunc) (int ident);
	texture *(*Texture) (texture *def, int ident);
	int ident;
} ShopRegion_t;

int notenoughcash;

SIRoute_t	*SIRoute;
SISquad_t	*SISquad;
SIEnemyType_t *SIEnemyType;
SIp_t SIp;
SImonster_t *SImonster;
SIbullet_t *SIbullet;
SIbullet_t *SIweapons;	//prototypes

qboolean SIShop;
qboolean lastlevel;
float deadtime;
float leveltime;

int livingmonsters;

texture SIplayertexture;	//both
texture *SIbaddietexture;	//game only
texture *SIbullettexture;	//game only
texture SIexplosiontexture;	//game only
texture SIhealthtexture;		//shop only
texture SIleaveshoptexture;	//shop only
texture SIshrinktexture;		//shop only
texture SIcannontexture;	//game+shop
texture SIsideshottexture;	//shop only
texture SIrapidtexture;
texture SIsavegametexture;
texture SIloadgametexture;
texture SIquittexture;
/*
sound SoundWin;
sound SoundLoose;
sound SoundFire;
sound SoundExplosion;
sound SoundHit;	//when we don't kill
*/
void SISPHealth (int ident)
{
	if (SIp.health >= 9)
		return;
	if (SIp.cash < 250)
	{
		notenoughcash = 250;
		return;
	}
	SIp.health++;
	SIp.cash -= 250;
}
qboolean SISPHealthThere (int ident)
{
	if (SIp.health < 9)
		return true;
	return false;
}

void SISPUpgrade1 (int ident)
{
	if (SIp.cannon[M_FORWARD].power >= weaponlevels-1)
		return;

	if (SIp.cash < 500)
	{
		notenoughcash = 250;
		return;
	}
	SIp.cannon[M_FORWARD].power++;
	SIp.cash -= 500;
}
texture *SISPUpgrade1Texture (texture *def, int ident)
{
	return &SIbullettexture[SIp.cannon[M_FORWARD].power+1];
}
qboolean SISPUpgrade1There (int ident)
{
	if (SIp.cannon[M_FORWARD].power < weaponlevels-1)
		return true;
	return false;
}

void SISPShrink (int ident)
{
	if (SIp.powerups & PUP_SHRUNKEN)	//can't reshrink
		return;

	if (SIp.cash < 100)
	{
		notenoughcash = 250;
		return;
	}
	SIp.powerups |= PUP_SHRUNKEN;
	SIp.cash -= 100;
}
bool SISPShrinkThere (int ident)
{
	if (SIp.powerups & PUP_SHRUNKEN)
		return false;
	return true;
}

void SISPCannon (int ident)
{
	int a;

	if (SIp.cash < 1500)
	{
		notenoughcash = 250;
		return;
	}

	for (a = FIRSTCANNON; a <= LASTCANNON; a++)
	{
		if (SIp.cannon[a].power == 0)
		{
			SIp.cannon[a].tex = &SIcannontexture;
			SIp.cannon[a].power = 1;

			SIp.cash -= 1500;
			return;
		}
	}
}

bool SISPCannonThere (int ident)
{
	int a;

	for (a = FIRSTCANNON; a <= LASTCANNON; a++)
	{
		if (SIp.cannon[a].power == 0)
		{
			return true;
		}
	}

	return false;
}

texture *SISPCannonUpgradeTexture (texture *def, int ident)
{
	return &SIbullettexture[SIp.cannon[ident].power];
}
void SISPCannonUpgrade(int ident)
{
	if (SIp.cannon[ident].power >= weaponlevels)
		return;

	if (SIp.cash < 600)
	{
		notenoughcash = 250;
		return;
	}
	SIp.cannon[ident].power++;	
	SIp.cash -= 600;
}
bool SISPCannonUpgradeThere(int ident)
{	
	if (SIp.cannon[ident].power >= weaponlevels || SIp.cannon[ident].power <= 0)
		return false;
	return true;
}

void SISPCannonBoost(int ident)
{
	if (SIp.cannon[ident].reloadtime <= 0.1f)
		return;

	if (SIp.cash < 600)
	{
		notenoughcash = 250;
		return;
	}
	SIp.cannon[ident].reloadtime -= 0.1f;	
	SIp.cash -= 600;
}
bool SISPCannonBoostThere(int ident)
{	
	if (SIp.cannon[ident].reloadtime <= 0.1f || SIp.cannon[ident].power <= 0)
		return false;
	return true;
}

void SISPRocket (int ident)
{
	int a;

	if (SIp.cash < 1500)
	{
		notenoughcash = 250;
		return;
	}

	for (a = FIRSTROCKET; a <= LASTROCKET; a++)
	{
		if (SIp.cannon[a].power == 0)
		{
			SIp.cannon[a].tex = &SIcannontexture;
			SIp.cannon[a].power = 1;

			SIp.cash -= 1500;
			return;
		}
	}
}

bool SISPRocketThere (int ident)
{
	int a;

	for (a = FIRSTROCKET; a <= LASTROCKET; a++)
	{
		if (SIp.cannon[a].power == 0)
		{
			return true;
		}
	}

	return false;
}

texture *SISPSideBurstTexture (texture *def, int ident)
{
	return &SIbullettexture[SIp.cannon[M_SIDE].power];
}
void SISPSideBurst (int ident)
{
	if (SIp.cannon[M_SIDE].power >= weaponlevels)
		return;

	if (SIp.cash < 1000)
	{
		notenoughcash = 250;
		return;
	}

	SIp.cash -= 1000;

	SIp.cannon[M_SIDE].power+=1;
}
bool SISPSideBurstThere (int ident)
{
	if (SIp.cannon[M_SIDE].power >= weaponlevels)
		return false;
	return true;
}

void SISPRapidFire (int ident)
{
	if (SIp.cannon[M_FORWARD].reloadtime <= 0.1)
		return;

	if (SIp.cash < 250)
	{
		notenoughcash = 250;
		return;
	}

	SIp.cash -= 250;

	SIp.cannon[M_FORWARD].reloadtime -= 0.1f;
}
bool SISPRapidFireThere (int ident)
{
	if (SIp.cannon[M_FORWARD].reloadtime <= 0.1)
		return false;
	return true;
}

void NextLevel (void);
void LeaveShop (int ident)
{
	NextLevel();
}

bool gamesaved = 2;
void SISaveGame(int ident)
{
	int a;
	texture handle;

	FS_Open("spaceinv/spaceinv.sav", &handle, 2);

	FS_Write(handle, &SIp.cash, sizeof(SIp.cash));
	FS_Write(handle, &SIp.powerups, sizeof(SIp.powerups));
	FS_Write(handle, &SIp.health, sizeof(SIp.health));
	FS_Write(handle, &SIlevel, sizeof(SIlevel));

	for (a = 0; a < MAXADDONS; a++)
	{
		FS_Write(handle, &SIp.cannon[a].power, sizeof(SIp.cannon[a].power));
		FS_Write(handle, &SIp.cannon[a].reloadtime, sizeof(SIp.cannon[a].reloadtime));
	}

	FS_Close(handle);

	gamesaved = true;
}

void SILoadGame(int ident)
{
	int a;
	int len;
	texture handle;

	len = FS_Open("spaceinv/spaceinv.sav", &handle, 1);
	if (len < 0)
		return;

	FS_Read(handle, &SIp.cash, sizeof(SIp.cash));
	FS_Read(handle, &SIp.powerups, sizeof(SIp.powerups));
	FS_Read(handle, &SIp.health, sizeof(SIp.health));
	FS_Read(handle, &SIlevel, sizeof(SIlevel));

	for (a = 0; a < MAXADDONS; a++)
	{
		FS_Read(handle, &SIp.cannon[a].power, sizeof(SIp.cannon[a].power));
		FS_Read(handle, &SIp.cannon[a].reloadtime, sizeof(SIp.cannon[a].reloadtime));

		if (SIp.cannon[a].power > weaponlevels)
			SIp.cannon[a].power = weaponlevels;

	}

	FS_Close(handle);
}

bool SILoadGameThere(int ident)
{
	texture handle;
	if (gamesaved = 2)
	{
		if (FS_Open("spaceinv/spaceinv.sav", &handle, 1) >= 0)
		{
			FS_Close(handle);
			gamesaved = true;
		}
		else
			gamesaved = false;
	}
	return gamesaved;	
}

bool SIFTRUE (int ident) {return true;}
texture *SIShopTexture (texture *def, int ident)
{
	return def;
}

ShopRegion_t ShopRegion[] =
{	
	{40,	40,		40,	40,	"3Leave Shop",				&SIleaveshoptexture,	SIFTRUE,			LeaveShop,		SIShopTexture		},
	{40,	80,		40,	40,	"3       Heal     (250)",	&SIhealthtexture,		SISPHealthThere,	SISPHealth,		SIShopTexture		},
	{40,	120,	40,	40,	"3   Rapid Fire   (250)",	&SIrapidtexture,		SISPRapidFireThere,	SISPRapidFire,	SIShopTexture		},
	{80,	40,		40,	40,	"3Upgrade Weapons (500)",	NULL,					SISPUpgrade1There,	SISPUpgrade1,	SISPUpgrade1Texture	},
	{80,	80,		40,	40,	"3      Shrink    (100)",	&SIshrinktexture,		SISPShrinkThere,	SISPShrink,		SIShopTexture		},
//	{80,	120,	40,	40,	"4Quit Game",				&SIquittexture,			SIFTRUE,			SIQuit,			SIShopTexture		},
	{120,	40,		40,	40,	"3   Side Cannon (1500)",	&SIcannontexture,		SISPCannonThere,	SISPCannon,		SIShopTexture,	1	},
	{120,	80,		40,	40,	"3    Spreader   (1000)",	&SIsideshottexture,		SISPSideBurstThere,	SISPSideBurst,	SIShopTexture		},
	{120,	80,		20,	20,	"3    Spreader   (1000)",	NULL,					SISPSideBurstThere,	SISPSideBurst,	SISPSideBurstTexture},
	{120,	120,	40,	40,	"3Save Game",				&SIsavegametexture,		SIFTRUE,			SISaveGame,		SIShopTexture		},
	{120,	160,	40,	40,	"3Load Game",				&SIloadgametexture,		SILoadGameThere,	SILoadGame,		SIShopTexture		},
	{80,	160,	40,	40,	"3RocketLauncher (1500)",	&SIcannontexture,		SISPRocketThere,	SISPRocket,		SIShopTexture,	1	},

	{160,	40,		40,	40,	"3Upgrade Cannon1(600)",	NULL,					SISPCannonUpgradeThere,	SISPCannonUpgrade,	SISPCannonUpgradeTexture, 0},
	{200,	40,		40,	40,	"3Upgrade Cannon2(600)",	NULL,					SISPCannonUpgradeThere,	SISPCannonUpgrade,	SISPCannonUpgradeTexture, 1},
	{240,	40,		40,	40,	"3Upgrade Cannon3(600)",	NULL,					SISPCannonUpgradeThere,	SISPCannonUpgrade,	SISPCannonUpgradeTexture, 2},
	{280,	40,		40,	40,	"3Upgrade Cannon4(600)",	NULL,					SISPCannonUpgradeThere,	SISPCannonUpgrade,	SISPCannonUpgradeTexture, 3},
	{320,	40,		40,	40,	"3Upgrade Cannon5(600)",	NULL,					SISPCannonUpgradeThere,	SISPCannonUpgrade,	SISPCannonUpgradeTexture, 4},
	{360,	40,		40,	40,	"3Upgrade Cannon6(600)",	NULL,					SISPCannonUpgradeThere,	SISPCannonUpgrade,	SISPCannonUpgradeTexture, 5},
	{400,	40,		40,	40,	"3Upgrade Cannon7(600)",	NULL,					SISPCannonUpgradeThere,	SISPCannonUpgrade,	SISPCannonUpgradeTexture, 6},
	{440,	40,		40,	40,	"3Upgrade Cannon8(600)",	NULL,					SISPCannonUpgradeThere,	SISPCannonUpgrade,	SISPCannonUpgradeTexture, 7},
	{480,	40,		40,	40,	"3Upgrade Cannon9(600)",	NULL,					SISPCannonUpgradeThere,	SISPCannonUpgrade,	SISPCannonUpgradeTexture, 8},
	{520,	40,		40,	40,	"3Upgrade Cannon10(600)",	NULL,					SISPCannonUpgradeThere,	SISPCannonUpgrade,	SISPCannonUpgradeTexture, 9},
	{560,	40,		40,	40,	"3Upgrade Cannon11(600)",	NULL,					SISPCannonUpgradeThere,	SISPCannonUpgrade,	SISPCannonUpgradeTexture, 10},
	{600,	40,		40,	40,	"3Upgrade Cannon12(600)",	NULL,					SISPCannonUpgradeThere,	SISPCannonUpgrade,	SISPCannonUpgradeTexture, 11},

	{160,	80,		40,	40,	"3 Boost Cannon1 (600)",	&SIrapidtexture,					SISPCannonBoostThere,	SISPCannonBoost,	SIShopTexture, 0},
	{200,	80,		40,	40,	"3 Boost Cannon2 (600)",	&SIrapidtexture,					SISPCannonBoostThere,	SISPCannonBoost,	SIShopTexture, 1},
	{240,	80,		40,	40,	"3 Boost Cannon3 (600)",	&SIrapidtexture,					SISPCannonBoostThere,	SISPCannonBoost,	SIShopTexture, 2},
	{280,	80,		40,	40,	"3 Boost Cannon4 (600)",	&SIrapidtexture,					SISPCannonBoostThere,	SISPCannonBoost,	SIShopTexture, 3},
	{320,	80,		40,	40,	"3 Boost Cannon5 (600)",	&SIrapidtexture,					SISPCannonBoostThere,	SISPCannonBoost,	SIShopTexture, 4},
	{360,	80,		40,	40,	"3 Boost Cannon6 (600)",	&SIrapidtexture,					SISPCannonBoostThere,	SISPCannonBoost,	SIShopTexture, 5},
	{400,	80,		40,	40,	"3 Boost Cannon7 (600)",	&SIrapidtexture,					SISPCannonBoostThere,	SISPCannonBoost,	SIShopTexture, 6},
	{440,	80,		40,	40,	"3 Boost Cannon8 (600)",	&SIrapidtexture,					SISPCannonBoostThere,	SISPCannonBoost,	SIShopTexture, 7},
	{480,	80,		40,	40,	"3 Boost Cannon9 (600)",	&SIrapidtexture,					SISPCannonBoostThere,	SISPCannonBoost,	SIShopTexture, 8},
	{520,	80,		40,	40,	"3 Boost Cannon10(600)",	&SIrapidtexture,					SISPCannonBoostThere,	SISPCannonBoost,	SIShopTexture, 9},
	{560,	80,		40,	40,	"3 Boost Cannon11(600)",	&SIrapidtexture,					SISPCannonBoostThere,	SISPCannonBoost,	SIShopTexture, 10},
	{600,	80,		40,	40,	"3 Boost Cannon12(600)",	&SIrapidtexture,					SISPCannonBoostThere,	SISPCannonBoost,	SIShopTexture, 11},
};

ShopRegion_t *CurrentRegion = &ShopRegion[0];

SIbullet_t *SI_NewBullet (int bulletlevel)
{
	int a;	
	for (a = 0; a < MAXBULLETS; a++)
	{
		if (!SIbullet[a].inuse)
		{
#if 0
			memset(&SIbullet[a], 0, sizeof(SIbullet_t));			
			SIbullet[a].damage = bulletlevel+1;
			SIbullet[a].inuse = true;
			SIbullet[a].alpha = 1.0;
			SIbullet[a].tex = &SIbullettexture[bulletlevel];
#else
			if (bulletlevel < 0)
			{
				memcpy(&SIbullet[a], &SIweapons[0], sizeof(SIbullet_t));
				SIbullet[a].type = bulletlevel;
				SIbullet[a].alphachange+=0.05f;
			}
			else			
				memcpy(&SIbullet[a], &SIweapons[bulletlevel], sizeof(SIbullet_t));
			SIbullet[a].inuse = true;						
#endif
 			return &SIbullet[a];
		}
	}
	return NULL;
}

SIbullet_t *SI_NewExplosion (float cx, float cy, float size)
{
	int a;
	for (a = 0; a < MAXBULLETS; a++)
	{
		if (!SIbullet[a].inuse)
		{
			memset(&SIbullet[a], 0, sizeof(SIbullet_t));
			SIbullet[a].inuse = true;
			SIbullet[a].alpha = (float)0.005;
			SIbullet[a].alphachange = (float)0.01;
			SIbullet[a].tex = &SIexplosiontexture;

			SIbullet[a].width = size;
			SIbullet[a].height = size;
			SIbullet[a].xpos = cx - size/2;
			SIbullet[a].ypos = cy - size/2;
			return &SIbullet[a];
		}
	}
	return NULL;
}

float random(void)
{		
	return (float)(rand() & 0x7fff) / (float)0x7fff;
}

void Draw_String2C(int x, int y, char *string, int extraparam)
{
	string++;
	x -= strlen(string)*4;
	while(*string)
	{
		Draw_Character(x+=8, y, *string++);
	}
}

void Draw_Picture(texture tex, float x, float y, float w, float h)
{
	Draw_Image(x, y, w, h, 0, 0, 1, 1, tex);
}

int levelnametime = 0;
int frame = 0;
void SI_2D (void)
{	
	int a;
	int b;
	int i;
	float x;
	float y;

	frame++;
	if (SIShop)
	{
		if (lastlevel)
		{
			Draw_Colour4f(1, 1, 1, 1);
			Draw_String2C(vid.width / 2, vid.height / 3, "3You have compleated the game.", 2);
			Draw_String2C(vid.width / 2, vid.height / 2, "3Well done.", 2);
			Draw_String2C(vid.width / 2, (vid.height / 3)*2, "3Press any key to restart.", 2);

			Draw_String2C(vid.width / 2, vid.height-8, va("3Cash: %i", SIp.cash), 2);
			return;
		}
		if (SIp.powerups & PUP_SHRUNKEN)
		{
			SIp.width = 16;
			SIp.height = 16;
		}
		else
		{
			SIp.width = 32;
			SIp.height = 32;
		}


		for (a = 0; a < sizeof(ShopRegion)/sizeof(ShopRegion_t); a++)
		{			
			if ((*ShopRegion[a].AppearCondition) (ShopRegion[a].ident))
				Draw_Image(ShopRegion[a].x, ShopRegion[a].y, ShopRegion[a].width, ShopRegion[a].height, 0, 0, 1, 1, *(*ShopRegion[a].Texture) (ShopRegion[a].tex, ShopRegion[a].ident));
		}

		if (SIp.health < 4)
			Draw_String2C(8, 8, va("4%i", SIp.health), 2);
		else
			Draw_String2C(8, 8, va("3%i", SIp.health), 2);
		
		Draw_Picture(SIplayertexture, SIp.x, SIp.y, SIp.width, SIp.height);
		for (a = 0; a < MAXADDONS; a++)
		{
			if (SIp.cannon[a].power)
			{
				if (SIp.cannon[a].tex)
					Draw_Picture(*SIp.cannon[a].tex, SIp.x + SIp.width*SIp.cannon[a].xoff, SIp.y + SIp.width*SIp.cannon[a].yoff, SIp.width, SIp.height);
			}
		}
//		if (SIp.powerups & PUP_CANNON)
//			Draw_Picture(SIcannontexture, SIp.x - SIp.width, SIp.y, SIp.width, SIp.height);
//		if (SIp.powerups & PUP_CANNON2)
//			Draw_Picture(SIcannontexture, SIp.x + SIp.width, SIp.y, SIp.width, SIp.height);

		if (notenoughcash)
		{
			notenoughcash--;			
			Draw_Colour4f(1, 1, 1, (float)notenoughcash / 250);
			Draw_String2C(vid.width / 2, vid.height / 2, "4Not enough cash!", 2);
		}
		Draw_Colour4f(1, 1, 1, 1);
		if (CurrentRegion)
			Draw_String2C(vid.width / 2, 8, CurrentRegion->text, 2);
		Draw_String2C(vid.width / 2, vid.height-8, va("3Cash: %i", SIp.cash), 2);
		return;
	}

	if (SIp.health > 0)
	{
		Draw_Colour4f(1, 1, 1,				1);
		/*		

		was a flame trail. :(
		grDisable(GL_TEXTURE_2D);
		grShadeModel(GL_SMOOTH);
		grBegin(GL_TRIANGLES);

		x = SIp.x+SIp.width/2;
		y = SIp.y+SIp.height;

		i = 12+rand()%8;

		grColor4f(0, 0, 1, 1);
		grVertex2f(x, y);
		grColor4f(1, 0, 1, 0);
		grVertex2f(x, y-i/2);
		grVertex2f(x+i, y);

		grColor4f(0, 0, 1, 1);
		grVertex2f(x, y);
		grColor4f(1, 0, 1, 0);
		grVertex2f(x+i, y);
		grVertex2f(x, y+i*2);

		grColor4f(0, 0, 1, 1);
		grVertex2f(x, y);
		grColor4f(1, 0, 1, 0);
		grVertex2f(x-i, y);
		grVertex2f(x, y+i*2);

		grColor4f(0, 0, 0, 1);
		grVertex2f(x, y);
		grColor4f(1, 0, 1, 0);
		grVertex2f(x, y-i/2);
		grVertex2f(x-i, y);

		/*
		grColor4f(1, 1, 1, 0);
		grVertex2f(x+8, y);
		grColor4f(1, 1, 1,				1);
		grVertex2f(x, y);
		grVertex2f(x, 0);
		grColor4f(1, 1, 1, 0);
		grVertex2f(x+8, 0);

		grColor4f(1, 1, 1,				1);
		grVertex2f(x, y);
		grColor4f(1, 1, 1, 0);
		grVertex2f(x-8, y);
		grVertex2f(x-8, 0);
		grColor4f(1, 1, 1,				1);
		grVertex2f(x, 0);
		

		grColor4f(1, 1, 1, 0);
		grVertex2f(x+8, y);
		grColor4f(1, 1, 1,				1);
		grVertex2f(x, y);
		grColor4f(1, 1, 1, 0);
		grVertex2f(x, y+8);
		grVertex2f(x+8, y+8);

		grVertex2f(x, y+8);
		grColor4f(1, 1, 1,				1);
		grVertex2f(x, y);
		grColor4f(1, 1, 1, 0);
		grVertex2f(x-8, y);
		grVertex2f(x-8, y+8);
		*/
/*
		grEnd();
		Draw_Colour4f(1, 1, 1, 1);
*/
		Draw_Picture(SIplayertexture, SIp.x, SIp.y, SIp.width, SIp.height);
		for (a = 0; a < MAXADDONS; a++)
		{
			if (SIp.cannon[a].power)
			{
				if (SIp.cannon[a].tex)
					Draw_Picture(*SIp.cannon[a].tex, SIp.x + SIp.width*SIp.cannon[a].xoff, SIp.y + SIp.width*SIp.cannon[a].yoff, SIp.width, SIp.height);
			}
		}
	}

	for (a = 0; a < MAXMONSTERS; a++)
	{
		if (SImonster[a].health > 0)
		{
			Draw_Picture(*SImonster[a].EnemyType->picture, SImonster[a].xpos, SImonster[a].ypos, SImonster[a].width, SImonster[a].height);
		}
	}

	//grEnable(GL_BLEND);
	for (a = 0; a < MAXBULLETS; a++)
	{
		if (SIbullet[a].inuse)
		{
			switch (SIbullet[a].type)
			{
			case 1:
				for (b = 0; b < SIbullet[a].charge; b++)
				{
					Draw_Colour4f(random(), random(), random(), SIbullet[a].alpha);
					Draw_Line (SIbullet[a].xpos+SIbullet[a].width/2,
						SIbullet[a].ypos+SIbullet[a].height/2,
						SIbullet[a].xpos+SIbullet[a].width/2+(float)sin((frame+2)*(a+1)*(b+1))*SIbullet[a].width,
						SIbullet[a].ypos+SIbullet[a].height/2+(float)cos((frame+2)*(a+1)*(b+1))*SIbullet[a].height);
				}
				break;

			case 2:
				x=realtime*50;

				Draw_Colour4f(1, 1, 1, SIbullet[a].alpha);
				Draw_Picture(*SIbullet[a].tex, SIbullet[a].xpos, 0, SIbullet[a].width, SIbullet[a].ypos+SIbullet[a].height);

				break;

/*			case 3:
				x=realtime*50;
				grColor4f(1, 1, 1, SIbullet[a].alpha);

				grDisable(GL_TEXTURE_2D);
				grBegin(GL_LINE_STRIP);
//				grVertex2f(SIbullet[a].xpos, SIbullet[a].ypos);
				for (y = SIbullet[a].ypos; y>0; y-=SIbullet[a].yvel*5+0.2f,x+=1)
					grVertex2f((float)SIbullet[a].xpos+(float)SIbullet[a].charge*(float)sin(x), y);
				
//				for (y = SIbullet[a].ypos; y>0; y-=25,x+=1)
//					grVertex2f((float)SIbullet[a].xpos+(float)SIbullet[a].charge*(float)sin(x), y);				

//				for (y = SIbullet[a].ypos; y>0; y-=25,x+=1)
//					grVertex2f((float)SIbullet[a].xpos+(float)SIbullet[a].charge*(float)sin(x), y);
				grEnd();
				grEnable(GL_TEXTURE_2D);
				break;
*/
			default:
				Draw_Colour4f(1, 1, 1, SIbullet[a].alpha);
				Draw_Picture(*SIbullet[a].tex, SIbullet[a].xpos, SIbullet[a].ypos, SIbullet[a].width, SIbullet[a].height);
				break;
			}
		}
	}
	Draw_Colour4f(1, 1, 1, 1);

	if (SIp.health <= 0)
		Draw_String2C(vid.width / 2, vid.height / 2, "4You LOOSE!", 2);
	else if (livingmonsters == 0)
	{
		Draw_String2C(vid.width / 2, vid.height / 2, "4You WIN!", 2);
		if (SIp.y + SIp.height < 0)
			Draw_String2C(vid.width / 2, (vid.height / 4) * 3, "3Press space!", 2);
	}
	else if (levelnametime)
	{
		Draw_Colour4f(1, 1, 1, (float)levelnametime/500);
		levelnametime--;
		Draw_String2C(vid.width/2, vid.height/2, SILevelName, 2);
		Draw_Colour4f(1, 1, 1, 1);
	}

	Draw_String2C(vid.width / 2, 4, va("3%i", SIp.cash), 1);
	if (SIp.health < 4)
		Draw_String2C(8, 8, va("4%i", SIp.health), 2);
	else
		Draw_String2C(8, 8, va("3%i", SIp.health), 2);
}

void SI_LoadTextures (void)
{
	int a;
	for (a = 0; a < monsterpics; a++)
		SIbaddietexture[a]	= Draw_LoadImage(va("spaceinv/enemy%i", a+1), false);
	for (a = 0; a < weaponlevels;a++)
		SIbullettexture[a]	= Draw_LoadImage(va("spaceinv/gun%i", a+1), false);
	SIplayertexture		= Draw_LoadImage("spaceinv/siplayer", false);
	SIexplosiontexture	= Draw_LoadImage("spaceinv/bang", false);
	SIhealthtexture		= Draw_LoadImage("spaceinv/health", false);
	SIleaveshoptexture	= Draw_LoadImage("spaceinv/leaveshop", false);
	SIshrinktexture		= Draw_LoadImage("spaceinv/shrink",  false);
	SIcannontexture		= Draw_LoadImage("spaceinv/cannon", false);
	SIquittexture		= Draw_LoadImage("spaceinv/quit", false);
	SIsavegametexture	= Draw_LoadImage("spaceinv/save", false);
	SIloadgametexture	= Draw_LoadImage("spaceinv/load", false);	
	SIsideshottexture	= Draw_LoadImage("spaceinv/sideshot", false);
	SIrapidtexture		= Draw_LoadImage("spaceinv/rapid", false);	
}

//Add side cannons?
bool SIHitPlayer(float x, float y, float width, float height)
{		
	if (x + width > SIp.x && x < SIp.x + SIp.width && y + height > SIp.y && y < SIp.y + SIp.height)
		return true;
	else
		return false;
}

SImonster_t *SIHitEnemy(float x, float y, float width, float height)
{
	int a;
	for (a = 0; a < MAXMONSTERS; a++)
	{
		if (SImonster[a].health)
		{
			if (x + width > SImonster[a].xpos && x < SImonster[a].xpos + SImonster[a].width && y + height > SImonster[a].ypos && y < SImonster[a].ypos + SImonster[a].height)
				return &SImonster[a];
		}
	}
	return NULL;
}

void SIKillEnemy(SImonster_t *en)
{
	en->health = 0;
	livingmonsters--;

	SI_NewExplosion(en->xpos + en->width/2, en->ypos+ en->height/2, (en->width + en->height)/2);

	SIp.cash += en->EnemyType->reward;

	Sound_Start(SoundExplosion);

	if (livingmonsters <= 0)
		Sound_Start(SoundWin);
}

void SIHurtPlayer(int dam)
{
	if (SIp.health <= 0)	//already dead
		return;
	SIp.health -= dam;
	if (SIp.health < 0)
		SIp.health = 0;	//no negative health
	if (SIp.health <= 0)	//if final blow...
	{
		SI_NewExplosion(SIp.x + SIp.width/2, SIp.y + SIp.height/2, (SIp.width + SIp.height));
		Sound_Start(SoundLoose);

		deadtime = realtime + 4.0f;
	}
	else
		Sound_Start(SoundHit);
}

float nextthink;

void SI_MouseMove(int x, int y);
void SI_Main(int mousex, int mousey)
{
	int a;
	int i;
	int tm;
	float tmdist;

	SIbullet_t *bul;
	SImonster_t *en;

	vec3_t v;

	if (nextthink > realtime)
	{
//		Con_Printf("no time\n");
		return;
	}
//	Con_Printf("time\n");
	nextthink += 0.02f;

	if (nextthink < realtime-1)	//don't run more than a second behind
		nextthink = realtime-1;

	if (SIShop)
	{		
		if (lastlevel)
		{
//			Con_Printf("Lastlevel\n");
			return;
		}

//		Con_Printf("%i (%f %f)\n", SIp.contols, SIp.x, SIp.y);

		if (!SIp.health)
			SIp.health=1;

		if (SIp.contols & CONT_LEFTKEY)
			SIp.x -= PLAYERSHIPSPEEDX;
		if (SIp.contols & CONT_RIGHTKEY)
			SIp.x += PLAYERSHIPSPEEDX;

		if (SIp.x < 0)
			SIp.x = 0;
		if (SIp.x + SIp.width >= vid.width)
			SIp.x = vid.width - SIp.width;

		if (SIp.contols & CONT_DOWNKEY)
			SIp.y += PLAYERSHIPSPEEDY;
		if (SIp.contols & CONT_UPKEY)
			SIp.y -= PLAYERSHIPSPEEDY;

		if (SIp.y < 0)
			SIp.y = 0;
		if (SIp.y + SIp.height >= vid.height)
			SIp.y = vid.height - SIp.height;

		CurrentRegion = NULL;
		for (a = 0; a < sizeof(ShopRegion) / sizeof(ShopRegion_t); a++)
		{			
			if (SIp.x+SIp.width/2 < ShopRegion[a].x + ShopRegion[a].width && SIp.x+SIp.width/2 > ShopRegion[a].x &&
				SIp.y+SIp.height/2 < ShopRegion[a].y + ShopRegion[a].height && SIp.y+SIp.height/2 > ShopRegion[a].y)
			{
				if ((*ShopRegion[a].AppearCondition) (ShopRegion[a].ident))
				{
					CurrentRegion = &ShopRegion[a];				
					break;
				}
			}
		}

		if (SIp.contols & CONT_FIREKEY && CurrentRegion)
		{
			(*CurrentRegion->CallFunc) (CurrentRegion->ident);
			SIp.contols &= ~CONT_FIREKEY;
		}		

		return;
	}

	leveltime += 0.02f;


	if (SIp.health > 0)
	{
		if (SIp.contols & CONT_LEFTKEY || (SIp.contols & CONT_MOUSE && SIp.x+SIp.width/2 > mousex))
			SIp.x -= PLAYERSHIPSPEEDX;	
		if (SIp.contols & CONT_RIGHTKEY || (SIp.contols & CONT_MOUSE && SIp.x+SIp.width/2 < mousex))
			SIp.x += PLAYERSHIPSPEEDX;

		if (SIp.x < 0)
			SIp.x = 0;
		if (SIp.x + SIp.width >= vid.width)
			SIp.x = vid.width - SIp.width;

		if (livingmonsters > 0)
		{
			if (SIp.contols & CONT_DOWNKEY || (SIp.contols & CONT_MOUSE && SIp.y+SIp.height/2 < mousey))
				SIp.y += PLAYERSHIPSPEEDY;
			if (SIp.contols & CONT_UPKEY || (SIp.contols & CONT_MOUSE && SIp.y+SIp.height/2 > mousey))
				SIp.y -= PLAYERSHIPSPEEDY;

			if (SIp.y < (vid.height / 2))
				SIp.y = (float)(vid.height / 2);
			if (SIp.y + SIp.height >= vid.height)
				SIp.y = vid.height - SIp.height;
		}
		else
		{
			SIp.y -= PLAYERSHIPSPEEDY;
		}

		if (SIp.contols & CONT_FIREKEY)
		{		
			/*
  			if (bul = SI_NewBullet(SIp.weaponpower))
			{						

				Sound_Start(SoundFire);

				bul->ypos = SIp.y - bul->height;
				bul->xpos = SIp.x + (SIp.width - bul->width) / 2;
				bul->xvel = 0;

				SIp.refire = SIp.reloadtime;
				*/

#if 1
				for (a = FIRSTCANNON; a <= LASTCANNON; a++)
				{
					if (SIp.cannon[a].power && SIp.cannon[a].refire < leveltime)
					{						
						if (bul = SI_NewBullet(SIp.cannon[a].power - 1))
						{
							bul->ypos = SIp.y - bul->height;
							bul->xpos = SIp.x + SIp.width*SIp.cannon[a].xoff + (SIp.width - bul->width) / 2;		
							bul->xvel = 0;

							SIp.cannon[a].refire = leveltime + SIp.cannon[a].reloadtime;

							Sound_Start(SoundFire);
						}
					}	
				}

				for (a = FIRSTCENTRALMOD; a <= LASTCENTRALMOD; a++)
				{
					if (SIp.cannon[a].power && SIp.cannon[a].refire < leveltime)
					{						
						if (bul = SI_NewBullet(SIp.cannon[a].power - 1))
						{
							bul->ypos = SIp.y - bul->height;
							bul->xpos = SIp.x + SIp.width*SIp.cannon[a].xoff + (SIp.width - bul->width) / 2;		
							bul->xvel = 0;							

							SIp.cannon[a].refire = leveltime + SIp.cannon[a].reloadtime;

							Sound_Start(SoundFire);
						}
					}	
				}

				
				for (a = FIRSTROCKET; a <= LASTROCKET; a++)
				{
					if (SIp.cannon[a].power && SIp.cannon[a].refire < leveltime)
					{						
						if (bul = SI_NewBullet(-1))
						{
							bul->ypos = SIp.y - bul->height;
							bul->xpos = SIp.x + SIp.width*SIp.cannon[a].xoff + (SIp.width - bul->width) / 2;		
							bul->xvel = 0;
							bul->yvel = -1;

							SIp.cannon[a].refire = leveltime + SIp.cannon[a].reloadtime;

							Sound_Start(SoundFire);
						}
					}	
				}

#else
				if (SIp.powerups & PUP_CANNON)
				{
					bul = SI_NewBullet(SIp.weaponpower);
					if (bul)
					{
					bul->width = 10;
					bul->height = 10;
					bul->damage = 1;
					bul->ypos = SIp.y - bul->height;
					bul->xpos = SIp.x - SIp.width + (SIp.width - bul->width) / 2;
					bul->xvel = 0;
					bul->yvel = (float)0.004;
					bul->yaccel = (float)0.002;				
					}
				}
				if (SIp.powerups & PUP_CANNON2)
				{
					bul = SI_NewBullet(SIp.weaponpower);
					if (bul)
					{
						bul->width = 10;
						bul->height = 10;
						bul->damage = 1;
						bul->ypos = SIp.y - bul->height;
						bul->xpos = SIp.x + SIp.width + (SIp.width - bul->width) / 2;
						bul->xvel = 0;
						bul->yvel = (float)0.004;
						bul->yaccel = (float)0.002;
					}
				}
#endif
				/*
				if (SIp.sidegun)
				{					
					if (bul = SI_NewBullet(SIp.sidegun -1))
					{
						bul->ypos = SIp.y - bul->height;
						bul->xpos = SIp.x + (SIp.width - bul->width) / 2;
						bul->xvel = (float)(random()-0.5)*2;
					}
				}				
			}
			*/
		}
	}
	else
	{
		if (deadtime < realtime)
			SIRestartGame();
	}

	for (a = 0; a < MAXSQUADS; a++)
	{
		if (SISquad[a].number && SISquad[a].time < leveltime)
		{
			SISquad[a].time += SISquad[a].interval;

			for (i = 0; i < MAXMONSTERS; i++)
			{
				if (SImonster[i].health <= 0)
				{
					SImonster[i].routenum = SISquad[a].route;
					SImonster[i].destnum = 1;
					SImonster[i].width = SIEnemyType[SISquad[a].type].width;
					SImonster[i].height = SIEnemyType[SISquad[a].type].height;
					SImonster[i].xpos = ((SIRoute[SImonster[i].routenum].pos[0])[0] - SImonster[i].width/2)/100.f*vid.height;
					SImonster[i].ypos = ((SIRoute[SImonster[i].routenum].pos[0])[1] - SImonster[i].height/2)/100.f*vid.height;

					SImonster[i].EnemyType = &SIEnemyType[SISquad[a].type];
					SImonster[i].health = SIEnemyType[SISquad[a].type].health;
					SImonster[i].yvel = ENEMYSHIPSPEEDY;
					SImonster[i].xvel = (float)ENEMYSHIPSPEEDX;
					SISquad[a].number-=1;
					break;
				}
			}
		}
	}

	tm = -1;
	tmdist = 32767;
	for (a = 0; a < MAXMONSTERS; a++)
	{
		if (SImonster[a].health > 0)
		{			
			if (tmdist > sqrt((SIp.x - SImonster[a].xpos)*(SIp.x - SImonster[a].xpos)+(SIp.y - SImonster[a].ypos)*(SIp.y - SImonster[a].ypos)))
			{
				tm = a;
				tmdist = (float)sqrt((SIp.x - SImonster[a].xpos)*(SIp.x - SImonster[a].xpos)+(SIp.y - SImonster[a].ypos)*(SIp.y - SImonster[a].ypos));
			}
			if (SImonster[a].EnemyType->AI)
			{
				if (SImonster[a].xpos+SImonster[a].width/2 > SIp.x+SIp.width/2)
				{
					if (SImonster[a].xpos+SImonster[a].width/2 - 0.8 < SIp.x+SIp.width/2)
						SImonster[a].xvel = SIp.x+SIp.width/2-(SImonster[a].xpos+SImonster[a].width/2);
					else
						SImonster[a].xvel = (float)-0.8;
				}
				else if (SImonster[a].xpos < SIp.x)
				{					
					if (SImonster[a].xpos+SImonster[a].width/2 + 0.8 > SIp.x+SIp.width/2)
						SImonster[a].xvel = SIp.x+SIp.width/2-(SImonster[a].xpos+SImonster[a].width/2);
					else
						SImonster[a].xvel = (float)0.8;
				}

				SImonster[a].ypos += SImonster[a].yvel;
				SImonster[a].xpos += SImonster[a].xvel;
				SImonster[a].yvel = 0;

				if (SImonster[a].xpos < 0)
					SImonster[a].xpos = 0;
				if (SImonster[a].xpos + SImonster[a].width >= vid.width)
					SImonster[a].xpos = vid.width - SImonster[a].width;

				if (SIHitPlayer(SImonster[a].xpos, SImonster[a].ypos, SImonster[a].width, SImonster[a].height) && SIp.health > 0)
				{				
					SIHurtPlayer(SImonster[a].health);
					SIKillEnemy(&SImonster[a]);				
				}
				else if (random() < SImonster[a].EnemyType->FireProb && SIp.health > 0 && SImonster[a].EnemyType->shotdamage >= 0)
				{
					if (bul = SI_NewBullet(SImonster[a].EnemyType->shotdamage))
					{
						bul->yvel *= -1;
						bul->yvel -= SImonster[a].yvel;
						bul->yaccel *= -1;
						bul->xpos = SImonster[a].xpos + SImonster[a].width/2-bul->width/2;
						bul->ypos = SImonster[a].ypos + SImonster[a].height;
	//					bul->width = 10;
	//					bul->height = 10;
					}
				}
			}
			else
			{
				SImonster[a].ypos += SImonster[a].yvel;
				SImonster[a].xpos += SImonster[a].xvel;

				if (SImonster[a].xpos < 0)
					SImonster[a].xpos = 0;
				if (SImonster[a].xpos + SImonster[a].width >= vid.width)
					SImonster[a].xpos = vid.width - SImonster[a].width;

				if (SIHitPlayer(SImonster[a].xpos, SImonster[a].ypos, SImonster[a].width, SImonster[a].height) && SIp.health > 0)
				{				
					SIHurtPlayer(SImonster[a].health);
					SIKillEnemy(&SImonster[a]);				
				}
				else if (SImonster[a].ypos > vid.height)
				{
					SImonster[a].ypos = 0 - SImonster[a].height;
					SImonster[a].xpos = random() * vid.width;
				}
				else if (random() < SImonster[a].EnemyType->FireProb && SIp.health > 0 && SImonster[a].EnemyType->shotdamage >= 0)
				{
					if (bul = SI_NewBullet(SImonster[a].EnemyType->shotdamage))
					{
						bul->yvel *= -1;
						bul->yvel -= SImonster[a].yvel;
						bul->yaccel *= -1;
						bul->xpos = SImonster[a].xpos + SImonster[a].width/2-bul->width/2;
						bul->ypos = SImonster[a].ypos + SImonster[a].height;
	//					bul->width = 10;
	//					bul->height = 10;
					}
				}
				else if (random() < 0.001)
					SImonster[a].xvel = (float)ENEMYSHIPSPEEDX;
			}
			if (SIEnemyType[a].healthregen)
			{
				if (SImonster[a].health < SImonster[a].health)
				{
					if (SIEnemyType[a].healthregen)
						SIEnemyType[a].healthregen--;
					else
					{
						SIEnemyType[a].healthregen = SImonster[a].timetoregen;
						SIEnemyType[a].health++;
					}
				}
			}
		}	
	}

	for (a = 0; a < MAXBULLETS; a++)
	{
		if (SIbullet[a].inuse)
		{
			if (SIbullet[a].type == -2)
			{
				SIbullet[a].ypos += SIbullet[a].yvel;
				SIbullet[a].xpos += SIbullet[a].xvel;

				SIbullet[a].alpha += SIbullet[a].alphachange;
				if (SIbullet[a].alpha >= 1 && SIbullet[a].alphachange > 0)
					SIbullet[a].alphachange *= -1;
				else if (SIbullet[a].alphachange && SIbullet[a].alpha <= 0)
					SIbullet[a].inuse = false;
			}
			else if (SIbullet[a].type == -1)
			{
				if (tm >= 0)
				{
					v[0] = SImonster[tm].xpos+SImonster[tm].width/2 - SIbullet[a].xpos;
					v[1] = SImonster[tm].ypos+SImonster[tm].height/2 - SIbullet[a].ypos;
					v[2] = 0;
					vecNorm(v, v);

					if (bul = SI_NewBullet(-2))
					{
						bul->xvel = -v[0]*3;
						bul->yvel = -v[1]*3;
						bul->alphachange = 0.05f;
						bul->xpos = SIbullet[a].xpos;
						bul->ypos = SIbullet[a].ypos;
					}

					v[0] += SIbullet[a].xvel;
					v[1] += SIbullet[a].yvel;

					vecNorm(v, v);
					SIbullet[a].xvel = v[0]*5;
					SIbullet[a].yvel = v[1]*5;

				}
				SIbullet[a].ypos += SIbullet[a].yvel;
				SIbullet[a].xpos += SIbullet[a].xvel;

				if (en = SIHitEnemy(SIbullet[a].xpos, SIbullet[a].ypos, SIbullet[a].width, SIbullet[a].height))
				{
					en->health -= SIbullet[a].damage;
					if (en->health <= 0)
					{
						SIKillEnemy(en);
					}
					else
					{
						Sound_Start(SoundHit);
					}

					SIbullet[a].alpha = 0.5f;
					SIbullet[a].alphachange = 0.04f;
					SIbullet[a].tex = &SIexplosiontexture;
					SIbullet[a].xvel = 0;
					SIbullet[a].yvel = 0;
					SIbullet[a].damage = 0;
					SIbullet[a].yaccel = 0;
					SIbullet[a].charge = 0;
					SIbullet[a].type = 0;
				}

				if (SIbullet[a].ypos + SIbullet[a].height < 0 || SIbullet[a].ypos > vid.height)
					SIbullet[a].inuse = false;
			}
			else if (SIbullet[a].ypos + SIbullet[a].height < 0 || SIbullet[a].ypos > vid.height)
			{
				SIbullet[a].inuse = false;
			}
			else
			{
				SIbullet[a].yvel += SIbullet[a].yaccel;
				SIbullet[a].ypos -= SIbullet[a].yvel;
				SIbullet[a].xpos += SIbullet[a].xvel;

				if (SIbullet[a].type == 2)
				{
					if (en = SIHitEnemy(SIbullet[a].xpos, 0, SIbullet[a].width, SIbullet[a].ypos))
					{
						en->health -= SIbullet[a].damage;
						if (en->health <= 0)
						{
							SIKillEnemy(en);
						}
						else
						{
							Sound_Start(SoundHit);
						}

//						SIbullet[a].alpha = 0.5f;
//						SIbullet[a].alphachange = 0.04f;
//						SIbullet[a].tex = &SIexplosiontexture;
//						SIbullet[a].xvel = 0;
//						SIbullet[a].yvel = 0;
//						SIbullet[a].damage = 0;
//						SIbullet[a].yaccel = 0;
//						SIbullet[a].charge = 0;
//						SIbullet[a].type = 0;
					}
				}
				else if (SIbullet[a].yvel > 0)
				{
					if (en = SIHitEnemy(SIbullet[a].xpos, SIbullet[a].ypos, SIbullet[a].width, SIbullet[a].height))
					{
						en->health -= SIbullet[a].damage;
						if (en->health <= 0)
						{
							SIKillEnemy(en);
						}
						else
						{
							Sound_Start(SoundHit);
						}

						SIbullet[a].alpha = 0.5f;
						SIbullet[a].alphachange = 0.04f;
						SIbullet[a].tex = &SIexplosiontexture;
						SIbullet[a].xvel = 0;
						SIbullet[a].yvel = 0;
						SIbullet[a].damage = 0;
						SIbullet[a].yaccel = 0;
						SIbullet[a].charge = 0;
						SIbullet[a].type = 0;
					}
				}
				else if (SIbullet[a].yvel < 0)
				{
					if (SIHitPlayer(SIbullet[a].xpos, SIbullet[a].ypos, SIbullet[a].width, SIbullet[a].height))
					{
						SIHurtPlayer(SIbullet[a].damage);
						SIbullet[a].alpha = 0.5f;
						SIbullet[a].alphachange = 0.04f;
						SIbullet[a].tex = &SIexplosiontexture;
						SIbullet[a].xvel = 0;
						SIbullet[a].yvel = 0;
						SIbullet[a].damage = 0;
						SIbullet[a].yaccel = 0;
						SIbullet[a].charge = 0;
						SIbullet[a].type = 0;
					}
				}

				SIbullet[a].alpha += SIbullet[a].alphachange;
				if (SIbullet[a].alpha >= 1 && SIbullet[a].alphachange > 0)
					SIbullet[a].alphachange *= -1;
				else if (SIbullet[a].alphachange && SIbullet[a].alpha <= 0)
					SIbullet[a].inuse = false;
			}
		}
	}
}

void SI_KeyUp(int k)
{
	if (k == K_LEFTARROW)
		SIp.contols &= ~CONT_LEFTKEY;
	else if (k == K_RIGHTARROW)
		SIp.contols &= ~CONT_RIGHTKEY;
	else if (k == K_UPARROW)
		SIp.contols &= ~CONT_UPKEY;
	else if (k == K_DOWNARROW)
		SIp.contols &= ~CONT_DOWNKEY;
	else if (k == K_MOUSE1 || k == K_SPACE)
		SIp.contols &= ~CONT_FIREKEY;
	else if (k == K_MOUSE2)
		SIp.contols &= ~CONT_MOUSE;
}
void SI_KeyDown(int k)
{
	if (SIShop && lastlevel)
	{
		SIlevel = 0;
		lastlevel = false;
		return;
	}
	else if (livingmonsters <= 0 && SIp.y + SIp.height < 0 && SIShop == false)
	{
		SIShop = true;
		SIlevel+=1;
		SIp.x = ShopRegion[0].x + ShopRegion[0].width/2;
		SIp.y = ShopRegion[0].y + ShopRegion[0].height/2;
		return;
	}
	else if (SIp.health <= 0)
	{
		if (k == K_SPACE && !(SIp.contols & CONT_FIREKEY))
			deadtime += 1;
		return;
	}

	if (k == K_LEFTARROW)
		SIp.contols |= CONT_LEFTKEY;
	else if (k == K_RIGHTARROW)
		SIp.contols |= CONT_RIGHTKEY;
	else if (k == K_UPARROW)
		SIp.contols |= CONT_UPKEY;	
	else if (k == K_DOWNARROW)
		SIp.contols |= CONT_DOWNKEY;
	else if (k == K_MOUSE1 || k == K_SPACE)
		SIp.contols |= CONT_FIREKEY;
	else if (k == K_MOUSE2)
		SIp.contols |= CONT_MOUSE;
	else if (k == '1')
		SIp.health = 9;
	else if (k == '2')
		SIp.cash += 100;
	else if (k == K_ESCAPE)
		Menu_Control(0);
	else
		Con_Printf("key %i not recognised\n", k);

	Con_Printf("%i (%i)\n", SIp.contols, k);
}

void SI_MouseMove(int x, int y)
{
	static int ox;
	static int oy;
	if (SIShop && (ox != x || oy != y))
	{
		SIp.x = (float)x - SIp.width/2;
		SIp.y = (float)y - SIp.height/2;

		ox = x;
		oy = y;
	}
}

qboolean FS_GetS(char *buffer, int buffersize, qhandle_t handle)
{
	int i;
	buffersize--;
	for (i = 0; i < buffersize; i+=1)
	{
		if (FS_Read(handle, buffer+i, 1) <= 0) break;
		if (buffer[i] == '\n') break;
	}

	buffer[i] = '\0';

	if (!i)
		return false;
	return true;
}

void SI_Initialize(void)
{
	int a;

/*	SoundWin = Sound_LoadSound("spaceinv/sound/win.wav");
	SoundLoose = Sound_LoadSound("spaceinv/sound/loose.wav");
	SoundFire = Sound_LoadSound("spaceinv/sound/fire.wav");
	SoundExplosion = Sound_LoadSound("spaceinv/sound/explode.wav");
	SoundHit = Sound_LoadSound("spaceinv/sound/explode.wav");
*/
	if (SIEnemyType)	//if one of these is defined, they must all be
	{
		free(SIEnemyType);
		free(SImonster);
		free(SIbullet);		

		free(SIbaddietexture);
		free(SIbullettexture);
		SIbullettexture = NULL;

		free(SISquad);
		free(SIRoute);
	}
	if (SIweapons)
		free(SIweapons);

	{	
		bool section = false;
	//	FILE *F;
		char line[1024];
		char *s;
		char *val;
		int len;

		qhandle_t f;

		len = FS_Open("spaceinv/weapons.txt", &f, 1);
		if (len>=0)
		{
			a = -1;		
			while (1)
			{
				if (!FS_GetS(line, 1024, f))
					break;
	//			if (!fgets(line, 1024, F))
	//				break;	//eof

				s = line;
				while(*s == ' ' || *s == '\t')	//ignore indents
					s++;
				
				if (*s == '\n' || *s == '\r' || *s == '#')	//ignore comments/blank lines
					continue;

				val = s + strlen(s)-1;
				while (*val == '\n' || *val == '\r' || *val == ' ' || *val == '\t')
				{
					*val = 0;
					val--;
				}


				val = strchr(s, '=');
				if (val)
				{
					*val = 0;
					val++;
				}

				if (section == 2 && *s != '[')
				{
					if (!strcasecmp(s, "monsterpics"))
						monsterpics = atoi(val);
					else if (!strcasecmp(s, "maxmonsters"))
						MAXMONSTERS = atoi(val);
					else if (!strcasecmp(s, "maxbullets"))
						MAXBULLETS = atoi(val);
					else if (!strcasecmp(s, "maxroutepoints"))
						MAXROUTEPOINTS = atoi(val);
					else if (!strcasecmp(s, "maxroutes"))
						MAXROUTES = atoi(val);
					else if (!strcasecmp(s, "maxsquads"))
						MAXSQUADS = atoi(val);
					else
						Con_Printf("Bad command \"%s\" in \"%s\"\n", s, "spaceinv\\weapons.txt");
				}
				else if (section == 1 && *s != '[')
				{
					if (!strcasecmp(s, "width"))
						SIweapons[a].width = (float)atof(val);
					else if (!strcasecmp(s, "height"))
						SIweapons[a].height = (float)atof(val);
					else if (!strcasecmp(s, "yvel"))
						SIweapons[a].yvel = (float)atof(val);
					else if (!strcasecmp(s, "yaccel"))
						SIweapons[a].yaccel = (float)atof(val);
					else if (!strcasecmp(s, "damage"))
						SIweapons[a].damage = atoi(val);
					else if (!strcasecmp(s, "alpha"))
						SIweapons[a].alpha = (float)atof(val);
					else if (!strcasecmp(s, "alphachange"))
						SIweapons[a].alphachange = (float)atof(val);
					else if (!strcasecmp(s, "texturenum"))
					{
						if (!SIbullettexture)
						{
							SIbullettexture = malloc(sizeof(texture) * weaponlevels);
							memset(SIbullettexture, 0, sizeof(texture) * weaponlevels);
						}
						SIweapons[a].tex = &SIbullettexture[atoi(val)-1];	//allow different pictures
					}
					else if (!strcasecmp(s, "charge"))
						SIweapons[a].charge = atoi(val);	//allow different pictures
					else if (!strcasecmp(s, "type"))
						SIweapons[a].type = atoi(val);
					else
						Con_Printf("Bad command \"%s\" in \"%s\"\n", s, "spaceinv\\weapons.txt");
				}
				else if (!strcasecmp(s, "weapons"))			
				{
					weaponlevels = atoi(val);
	//				if (weaponlevels > SHOTLEVELS)
	//				{
	//					Log("Too many weapons set\n");
	//					weaponlevels = SHOTLEVELS;
	//				}

					SIweapons = malloc(sizeof(SIbullet_t) * weaponlevels);
					memset(SIweapons, 0, sizeof(SIbullet_t) * weaponlevels);
				}
				else if (!strcasecmp(s, "[weapon"))
				{
					section = 1;
					if (weaponlevels == 0)
						Sys_Error("SILoadWeapons: number of weapons not set yet.");
					a = atoi(val);
					if (a > SHOTLEVELS)
					{
						a=0;
						Con_Printf("Bad type\n");
					}
					else
						a-=1;
				}
				else if (!strcasecmp(s, "[info]"))
				{
					section = 2;
				}
				else
					Con_Printf("Bad command \"%s\" in \"%s\"\n", s, "spaceinv\\weapons.txt");

			}

			FS_Close(f);
		}
		else
		{
			//GameCompleate = true;
			//NextLevel = 0;
			Sys_Error("Couldn't open file\n");
		}
	}

	if (!SIbullettexture)
	{
		SIbullettexture = malloc(sizeof(texture) * weaponlevels);
		memset(SIbullettexture, 0, sizeof(texture) * weaponlevels);
	}

	SIEnemyType = malloc(sizeof(SIEnemyType_t) * ENEMYTYPES);
	memset(SIEnemyType, 0, sizeof(SIEnemyType_t) * ENEMYTYPES);
	SImonster = malloc(sizeof(SImonster_t) * MAXMONSTERS);
	memset(SImonster, 0, sizeof(SImonster_t) * MAXMONSTERS);
	SIbullet = malloc(sizeof(SIbullet_t) * MAXBULLETS);
	memset(SIbullet, 0, sizeof(SIbullet_t) * MAXBULLETS);

	SIbaddietexture = malloc(sizeof(texture) * ENEMYTYPES);
	memset(SIbaddietexture, 0, sizeof(texture) * ENEMYTYPES);

	SIRoute = malloc((sizeof(SIRoute_t)+(MAXROUTEPOINTS-1)*sizeof(vec3_t)) * MAXROUTES);
	memset(SIRoute, 0, (sizeof(SIRoute_t)+(MAXROUTEPOINTS-1)*sizeof(vec3_t)) * MAXROUTES);
	SISquad = malloc(sizeof(SISquad_t) * MAXSQUADS);
	memset(SISquad, 0, sizeof(SISquad_t) * MAXSQUADS);

	//loaded elsewhere
//	SIweapons = mmalloc(sizeof(SIbullet_t) * weaponlevels);

	SI_LoadTextures ();
 
	SIRestartGame ();
}

void NextLevel (void)
{
	int a;
//	int numenemysoftype[ENEMYTYPES] = {5, 5, 50};
	int etype = 0;

	SIEnemyType_t *et;

 	if (SIp.powerups & PUP_SHRUNKEN)
	{
		SIp.height = 16;
		SIp.width = 16;

		SIp.powerups &= ~PUP_SHRUNKEN;
	}
	else
	{
		SIp.height = 32;
		SIp.width = 32;
	}
	SIp.y = vid.height - SIp.height;
	SIp.x = (vid.width - SIp.width) / 2;	
	SIShop = false;
	deadtime = 0;

	nextthink = realtime;


	leveltime = 0;

	for (a = 0; a < MAXSQUADS; a++)
		SISquad[a].number = 0;

#if 1
{
	int i;
	int usedtypes = false;	
	int sectiontype=0;
	qhandle_t F;
	char line[1024];
	char *s;
	char *val;

	int len;
	int rofs = 0;

	len = FS_Open(va("spaceinv/level%i.txt", SIlevel+1), &F, 1);
	if (len < 0)
	{
		SIlevel = 0;
		len = FS_Open(va("spaceinv/level%i.txt", SIlevel+1), &F, 1);	//loop back to the start
	}
//	F = fopen(Sva("%sspaceinv\\level%i.txt", funcs->exe->gamepath, SIlevel+1), "rb");
	if (len>=0)
	{
		a = -1;
		memset(SIEnemyType, 0, sizeof(SIEnemyType));
//		memset(numenemysoftype, 0, sizeof(numenemysoftype));
		while (1)
		{
			if (!FS_GetS(line, 1024, F))
				break;	//eof

			s = line;
			while(*s == ' ' || *s == '\t')	//ignore indents
				s++;
			
			if (*s == '\n' || *s == '\r' || *s == '#')	//ignore comments/blank lines
				continue;

			val = s + strlen(s)-1;
			while (*val == '\n' || *val == '\r' || *val == ' ' || *val == '\t')
			{
				*val = 0;
				val--;
			}


			val = strchr(s, '=');
			if (val)
			{
				*val = 0;
				val++;
			}

			if (*s == '[')
			{
				if (!strcasecmp(s+1, "info]"))
				{
					sectiontype = 1;
				}
				else if (!strcasecmp(s+1, "type"))
				{					
					if (usedtypes == 0)
						Con_Printf("SINextLevel: Types not set yet");
					a = atoi(val);
					if (a > ENEMYTYPES || a < 1)
					{
						a=0;
						Con_Printf("Bad type\n");
					}
					else
						a-=1;

					memset(&SIEnemyType[a], 0, sizeof(SIEnemyType_t));

					sectiontype = 2;				
				}
				else if (!strcasecmp(s+1, "route"))
				{					
					a = atoi(val);
					if (a > ENEMYTYPES || a < 1)
					{
						a=0;
						Con_Printf("Bad route\n");
					}
					else
						a-=1;

					memset(&SIRoute[a], 0, sizeof(SIRoute_t)+(MAXROUTEPOINTS-1)*sizeof(vec3_t));

					sectiontype = 3;				
				}
				else if (!strcasecmp(s+1, "squad"))
				{					
					a = atoi(val);
					if (a > MAXSQUADS || a < 1)
					{
						a=0;
						Con_Printf("Bad squad\n");
					}
					else
						a-=1;

					memset(&SISquad[a], 0, sizeof(SISquad_t));

					sectiontype = 4;				
				}
				else
					Con_Printf("Bad block \"%s\" in \"%s\"\n", s, va("level%i.txt", SIlevel));
			}
			else if (sectiontype == 0)
			{
				if (!strcasecmp(s, "types"))			
					usedtypes = atoi(val);
				else
					Con_Printf("Bad command \"%s\" in \"%s\" (out of block)\n", s, va("level%i.txt", SIlevel));
			}
			else if (sectiontype == 1)
			{
				if (!strcasecmp(s, "lastlevel"))
					lastlevel = atoi(val);
				else if (!strcasecmp(s, "levelname"))
				{
					strcpy(SILevelName, val);
					levelnametime = 500;
				}
				else
					Con_Printf("Bad command \"%s\" in \"%s\"\n", s, va("level%i.txt", SIlevel));
			}			
			else if (sectiontype == 2)
			{
				if (!strcasecmp(s, "width"))
					SIEnemyType[a].width = (float)atof(val);
				else if (!strcasecmp(s, "height"))
					SIEnemyType[a].height = (float)atof(val);
				else if (!strcasecmp(s, "power"))
				{					
					SIEnemyType[a].shotdamage = atoi(val) - 1;
					if (SIEnemyType[a].shotdamage >= weaponlevels)
					{
						Con_Printf("Enemy %i has weapon number %i\n", a+1, SIEnemyType[a].shotdamage+1);
						SIEnemyType[a].shotdamage = weaponlevels-1;
					}
				}
				else if (!strcasecmp(s, "health"))
					SIEnemyType[a].health = atoi(val);
				else if (!strcasecmp(s, "reward"))
					SIEnemyType[a].reward = atoi(val);
				else if (!strcasecmp(s, "number"))
					SIEnemyType[a].number = atoi(val);
				else if (!strcasecmp(s, "ai"))
					SIEnemyType[a].AI = atoi(val);
				else if (!strcasecmp(s, "healthregen"))
					SIEnemyType[a].healthregen = atoi(val);
				else if (!strcasecmp(s, "picture"))
				{
					i = atoi(val) - 1;
					if (i < 0 || i >= monsterpics)
					{
						Sys_Errorf("Monster picture has the wrong value (%i)", i+1);
					}
					else
						SIEnemyType[a].picture = &SIbaddietexture[i];	//allow different pictures
				}
				else if (!strcasecmp(s, "fireprob"))
					SIEnemyType[a].FireProb = (float)atof(val);	//allow different pictures				
				else
					Con_Printf("Bad command \"%s\" in \"%s\"\n", s, va("level%i.txt", SIlevel));
			}
			else if (sectiontype == 3)
			{
				if (!strcasecmp(s, "coords"))
					SIRoute[a].numpoints = atoi(val);
				else if (*s == 'x' || *s == 'X')
					(SIRoute[a].pos[atoi(s+1)-1])[0] = (float)atof(val);
				else if (*s == 'y' || *s == 'Y')
					(SIRoute[a].pos[atoi(s+1)-1])[1] = (float)atof(val);
				else if (*s == 'z' || *s == 'Z')
					(SIRoute[a].pos[atoi(s+1)-1])[2] = (float)atof(val);
				else
					Con_Printf("Bad route command \"%s\" in \"%s\"\n", s, va("level%i.txt", SIlevel));
			}
			else if (sectiontype == 4)
			{
				if (!strcasecmp(s, "route"))
					SISquad[a].route = atoi(val)-1;
				else if (!strcasecmp(s, "type"))
					SISquad[a].type = atoi(val)-1;
				else if (!strcasecmp(s, "number"))
					SISquad[a].number = atoi(val);
				else if (!strcasecmp(s, "interval"))
					SISquad[a].interval = (float)atof(val);
				else if (!strcasecmp(s, "speed"))
					SISquad[a].speed = (float)atof(val);
				else if (!strcasecmp(s, "time"))
					SISquad[a].time = (float)atof(val);
				else
					Con_Printf("Bad squad command \"%s\" in \"%s\"\n", s, va("level%i.txt", SIlevel));
			}
			else
				Con_Printf("Bad command \"%s\" in \"%s\"\n", s, va("level%i.txt", SIlevel));

		}

		FS_Close(F);
	}
	else
	{
		//GameCompleate = true;
		//NextLevel = 0;
		Sys_Errorf("Couldn't open file\n", va("spaceinv/level%i.txt", SIlevel+1));
	}
}
#else

	for (a = 0; a < ENEMYTYPES; a++)
	{
		SIEnemyType[a].health = a+1;
		SIEnemyType[a].height = (float)(16*(a+1));
		SIEnemyType[a].width = (float)(16*(a+1));
		SIEnemyType[a].picture = &SIbaddietexture;
		SIEnemyType[a].shotpicture = &SIbullettexture[0];
		SIEnemyType[a].shotdamage = a-1;
		SIEnemyType[a].reward = (a+1) * 25;
	}
#endif

	memset(SImonster, 0, sizeof(*SImonster)*MAXMONSTERS);

	livingmonsters = 0;
	while (SIEnemyType[etype].number <= 0)
	{
		etype++;
		if (etype >= ENEMYTYPES)
			break;
	}
	for (a = 0; a < MAXMONSTERS; a++)
	{
		if (etype < ENEMYTYPES)
		{
			et = &SIEnemyType[etype];
			SImonster[a].EnemyType = et;
			SImonster[a].health = et->health;
			SImonster[a].xpos = random() * vid.width;
			SImonster[a].ypos = (random() * vid.height) / 2;
			SImonster[a].width = et->width;
			SImonster[a].height = et->height;
			SImonster[a].yvel = ENEMYSHIPSPEEDY;
			SImonster[a].xvel = (float)ENEMYSHIPSPEEDX;
			livingmonsters++;

			SIEnemyType[etype].number-=1;
			while (SIEnemyType[etype].number <= 0)
			{
				etype++;
				if (etype >= ENEMYTYPES)
					break;
			}
			if (SIEnemyType[etype].number <= 0)
				break;
		}
		else
			SImonster[a].health = 0;
	}
	for (a = 0; a < MAXSQUADS; a++)
		livingmonsters += SISquad[a].number;
	deadtime = 0;

	memset(SIbullet, 0, sizeof(SIbullet) * MAXBULLETS);

	for (a = 0; a < MAXADDONS; a++)
		SIp.cannon[a].refire = 0;
}

void SIRestartGame (void)
{
	int a;
	SIp.health = 9;
	SIp.cash = 500;
	SIp.powerups = 0;		

	SIp.height = 32;
	SIp.width = 32;

	SIp.y = (vid.height - SIp.height)/2;
	SIp.x = (vid.width - SIp.width) / 2;	

	for (a = 0; a < MAXADDONS; a++)
	{
		SIp.cannon[a].xoff = 0;
		SIp.cannon[a].yoff = 0;

		SIp.cannon[a].power = 0;
		SIp.cannon[a].reloadtime = 0.8f;

		SIp.cannon[a].tex = NULL;
	}

#if 1
	for (a = FIRSTCANNON; a <= LASTCANNON; a++)
	{
		SIp.cannon[a].xoff = (int)((float)a-FIRSTCANNON+1.5f) / 2.0f;
		if (a%2)
			SIp.cannon[a].xoff *= -1;
		else
			SIp.cannon[a].xoff+=1;
		SIp.cannon[a].yoff = 0;	

		SIp.cannon[a].tex = &SIcannontexture;
	}
	for (a = FIRSTROCKET; a <= LASTROCKET; a++)
	{
		SIp.cannon[a].xoff = (int)(a-FIRSTROCKET+1.5f) / 2.0f;
		SIp.cannon[a].xoff -= 0.5f;
		if (a%2)	
			SIp.cannon[a].xoff *= -1.0f;
		else
			SIp.cannon[a].xoff += 1.0f;
		SIp.cannon[a].yoff = 0;

		SIp.cannon[a].tex = &SIcannontexture;
	}
#else
	SIp.cannon[0].xoff = -1;
	SIp.cannon[1].xoff = 1;
	SIp.cannon[2].xoff = -2;
	SIp.cannon[3].xoff = 2;
#endif

	SIp.cannon[M_FORWARD].power = 1;
	SIp.cannon[M_FORWARD].tex = &SIplayertexture;

	SIlevel = 0;
	lastlevel = false;
	SIShop = true;		
	deadtime = 0;
	nextthink = 0;
}










int Plug_MenuEvent(int *args)
{

//	args[2]=(int)(args[2]*640.0f/vid.width);
//	args[3]=(int)(args[3]*480.0f/vid.height);

	switch(args[0])
	{
	case 0:	//draw
		SI_Main(args[2], args[3]);
		SI_2D();
		break;
	case 1:	//keydown
		SI_KeyDown(args[1]);
		break;
	case 2:	//keyup
		SI_KeyUp(args[1]);
		break;
	case 3:	//menu closed (this is called even if we change it).
		break;
	case 4:	//mousemove
		break;
	}

	return 0;
}

int Plug_Tick(int *args)
{
	realtime = args[0]/1000.0f;
	return true;
}

int Plug_ExecuteCommand(int *args)
{
	char cmd[256];
	Cmd_Argv(0, cmd, sizeof(cmd));
	if (!strcmp("spaceinv", cmd))
	{
		Cvar_SetFloat("gl_blend2d", 1);
		SI_LoadTextures();
		Menu_Control(1);
		return 1;
	}
	return 0;
}

int Plug_Init(int *args)
{
	if (Plug_Export("Tick", Plug_Tick) &&
		Plug_Export("ExecuteCommand", Plug_ExecuteCommand) &&
		Plug_Export("MenuEvent", Plug_MenuEvent))
	{

		K_UPARROW		= Key_GetKeyCode("uparrow");
		K_DOWNARROW		= Key_GetKeyCode("downarrow");
		K_LEFTARROW		= Key_GetKeyCode("leftarrow");
		K_RIGHTARROW	= Key_GetKeyCode("rightarrow");
		K_ESCAPE		= Key_GetKeyCode("escape");
		K_HOME			= Key_GetKeyCode("home");
		K_MOUSE1		= Key_GetKeyCode("mouse1");
		K_MOUSE2		= Key_GetKeyCode("mouse2");
		K_SHIFT			= Key_GetKeyCode("shift");
		K_SPACE			= Key_GetKeyCode("space");
		K_F1			= Key_GetKeyCode("f1");
		K_F2			= Key_GetKeyCode("f2");

		Cmd_AddCommand("spaceinv");

		SI_Initialize();
		SI_LoadTextures();

		return 1;
	}
	return 0;
}