mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-27 14:12:25 +00:00
127ce4a500
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@1689 fc73d0e0-1445-4013-8a0c-d673dee63da5
2313 lines
54 KiB
C
2313 lines
54 KiB
C
#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;
|
|
}
|