From 6c5c3545eccb4364e8ad3118d051f5db9ca66448 Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 6 Dec 2005 15:38:44 +0000 Subject: [PATCH] spaceinvaders! git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@1679 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- plugins/spaceinv/.cvsignore | 3 + plugins/spaceinv/compile.bat | 22 + plugins/spaceinv/install.bat | 5 + plugins/spaceinv/spaceinv.c | 2349 +++++++++++++++++++++++++++++++ plugins/spaceinv/spaceinv.dsp | 123 ++ plugins/spaceinv/spaceinv.q3asm | 5 + 6 files changed, 2507 insertions(+) create mode 100644 plugins/spaceinv/.cvsignore create mode 100644 plugins/spaceinv/compile.bat create mode 100644 plugins/spaceinv/install.bat create mode 100644 plugins/spaceinv/spaceinv.c create mode 100644 plugins/spaceinv/spaceinv.dsp create mode 100644 plugins/spaceinv/spaceinv.q3asm diff --git a/plugins/spaceinv/.cvsignore b/plugins/spaceinv/.cvsignore new file mode 100644 index 00000000..c1bcfc7a --- /dev/null +++ b/plugins/spaceinv/.cvsignore @@ -0,0 +1,3 @@ +Debug +Release +vm diff --git a/plugins/spaceinv/compile.bat b/plugins/spaceinv/compile.bat new file mode 100644 index 00000000..f2e9902f --- /dev/null +++ b/plugins/spaceinv/compile.bat @@ -0,0 +1,22 @@ +@echo off +call ..\paths.bat + +del vm\*.asm +rmdir vm +mkdir vm +cd vm +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g ../spaceinv.c +if errorlevel 1 goto end +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g ../../memory.c -DMEMSIZE=1048576 +if errorlevel 1 goto end +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g ../../plugin.c +if errorlevel 1 goto end +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g ../../qvm_api.c +if errorlevel 1 goto end +q3asm -f ../spaceinv + +:end + +cd .. + +pause \ No newline at end of file diff --git a/plugins/spaceinv/install.bat b/plugins/spaceinv/install.bat new file mode 100644 index 00000000..fb6a272f --- /dev/null +++ b/plugins/spaceinv/install.bat @@ -0,0 +1,5 @@ +@echo off +call ..\paths.bat +mkdir %PluginsDir% +copy vm\spaceinv.qvm %PluginsDir% +pause \ No newline at end of file diff --git a/plugins/spaceinv/spaceinv.c b/plugins/spaceinv/spaceinv.c new file mode 100644 index 00000000..1ae40081 --- /dev/null +++ b/plugins/spaceinv/spaceinv.c @@ -0,0 +1,2349 @@ +#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 +{ + qhandle_t *picture; + float width; + float height; + int health; + + float FireProb; + + int reward; + + int number; + + int AI; + int healthregen; + + int shotdamage; + qhandle_t *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; + qhandle_t *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; + + qhandle_t *tex; +} SIbullet_t; + +typedef struct ShopRegion_s +{ + float x; + float y; + float width; + float height; + + char *text; + + qhandle_t *tex; + qboolean (*AppearCondition) (int ident); + void (*CallFunc) (int ident); + qhandle_t *(*Texture) (qhandle_t *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; + +qhandle_t SIplayertexture; //both +qhandle_t *SIbaddietexture; //game only +qhandle_t *SIbullettexture; //game only +qhandle_t SIexplosiontexture; //game only +qhandle_t SIhealthtexture; //shop only +qhandle_t SIleaveshoptexture; //shop only +qhandle_t SIshrinktexture; //shop only +qhandle_t SIcannontexture; //game+shop +qhandle_t SIsideshottexture; //shop only +qhandle_t SIrapidtexture; +qhandle_t SIsavegametexture; +qhandle_t SIloadgametexture; +qhandle_t 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; +} +qhandle_t *SISPUpgrade1Texture (qhandle_t *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; + qhandle_t 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; + qhandle_t 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) +{ + qhandle_t 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(qhandle_t 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); + /* + 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: +/* grDisable(GL_TEXTURE_2D); + grBegin(GL_LINES); + for (b = 0; b < SIbullet[a].charge; b++) + { +// frame = (int)random() * 1000; + grColor4f(random(), random(), random(), SIbullet[a].alpha); +#if 1 + grVertex2f (SIbullet[a].xpos+SIbullet[a].width/2, SIbullet[a].ypos+SIbullet[a].height/2); +#else + grVertex2f (SIbullet[a].xpos+SIbullet[a].width/2+(float)sin((frame+1)*(a+1)*(b+1))*SIbullet[a].width, SIbullet[a].ypos+SIbullet[a].height/2+(float)cos((frame+1)*(a+1)*(b+1))*SIbullet[a].height); +#endif + grVertex2f (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); + } + grEnd(); + grEnable(GL_TEXTURE_2D); + break; +*/ +/* case 2: + x=realtime*50; + grColor4f(1, 1, 1, SIbullet[a].alpha); + + grDisable(GL_TEXTURE_2D); + grShadeModel(GL_SMOOTH); + grBegin(GL_QUADS); + + x = SIbullet[a].xpos+SIbullet[a].width/2; + y = SIbullet[a].ypos+SIbullet[a].height/2; + + grColor4f(1, 1, 1, 0); + grVertex2f(x+SIbullet[a].width, y); + grColor4f(1, 1, 1, SIbullet[a].alpha); + grVertex2f(x, y); + grVertex2f(x, 0); + grColor4f(1, 1, 1, 0); + grVertex2f(x+SIbullet[a].width, 0); + + grColor4f(1, 1, 1, SIbullet[a].alpha); + grVertex2f(x, y); + grColor4f(1, 1, 1, 0); + grVertex2f(x-SIbullet[a].width, y); + grVertex2f(x-SIbullet[a].width, 0); + grColor4f(1, 1, 1, SIbullet[a].alpha); + grVertex2f(x, 0); + + + grColor4f(1, 1, 1, 0); + grVertex2f(x+SIbullet[a].width, y); + grColor4f(1, 1, 1, SIbullet[a].alpha); + grVertex2f(x, y); + grColor4f(1, 1, 1, 0); + grVertex2f(x, y+SIbullet[a].height); + grVertex2f(x+SIbullet[a].width, y+SIbullet[a].height); + + grVertex2f(x, y+SIbullet[a].height); + grColor4f(1, 1, 1, SIbullet[a].alpha); + grVertex2f(x, y); + grColor4f(1, 1, 1, 0); + grVertex2f(x-SIbullet[a].width, y); + grVertex2f(x-SIbullet[a].width, y+SIbullet[a].height); + + grEnd(); + grEnable(GL_TEXTURE_2D); + 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 == K_F1) + SIp.health = 9; + else if (k == K_F2) + 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); + + 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")) +// SIweapons[a].tex = (int)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"); + } + } + + 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); + SIbullettexture = malloc(sizeof(texture) * weaponlevels); + memset(SIbullettexture, 0, sizeof(texture) * weaponlevels); + + 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); + + for (a = 0; a < weaponlevels; a++) + { + SIweapons[a].tex = &SIbullettexture[(int)SIweapons[a].tex]; + } + + //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(); + + return 1; + } + return 0; +} diff --git a/plugins/spaceinv/spaceinv.dsp b/plugins/spaceinv/spaceinv.dsp new file mode 100644 index 00000000..60706f0b --- /dev/null +++ b/plugins/spaceinv/spaceinv.dsp @@ -0,0 +1,123 @@ +# Microsoft Developer Studio Project File - Name="spaceinv" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=spaceinv - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "spaceinv.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "spaceinv.mak" CFG="spaceinv - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "spaceinv - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "spaceinv - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "spaceinv - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "spaceinv_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "spaceinv_EXPORTS" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"../../spaceinvx86.dll" + +!ELSEIF "$(CFG)" == "spaceinv - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "spaceinv_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "spaceinv_EXPORTS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib /nologo /dll /debug /machine:I386 /out:"D:\Quake\id1\plugins/spaceinvx86.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "spaceinv - Win32 Release" +# Name "spaceinv - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\plugin.c +# End Source File +# Begin Source File + +SOURCE=..\qvm_api.c +# End Source File +# Begin Source File + +SOURCE=.\spaceinv.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\plugin.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=..\plugin.def +# End Source File +# End Target +# End Project diff --git a/plugins/spaceinv/spaceinv.q3asm b/plugins/spaceinv/spaceinv.q3asm new file mode 100644 index 00000000..7104c427 --- /dev/null +++ b/plugins/spaceinv/spaceinv.q3asm @@ -0,0 +1,5 @@ +-o "spaceinv" +plugin +spaceinv +qvm_api +memory \ No newline at end of file