If you have comments or questions concerning this source file, discuss them in the forum.
/*
Copyright (c) 2002 Nicolai Haehnle
See the license.txt for details. If that file was not included in the
source distributions, please email <prefect@rtts.org>
*/
// game.h -- included by actual in-game stuff
#include "rtts.h"
#include "gui_panel.h"
#define TOTALFADETIME 800
#define TOTALPREWINTIME 1500
#define SHADOWFRACT (0.80)
#define SHADOWX(x) (320 + (((x) - 320) * SHADOWFRACT))
#define SHADOWY(y) (400 + (((y) - 400) * SHADOWFRACT))
// solves SHADOWY(y)+m=0
#define FIRSTSHADOWY(m) (400 - ((400+(m)) / SHADOWFRACT))
class AirPlayer;
typedef struct {
int money; // money earned
int moneymax; // total money in level
float shieldslost;
} eplrstats_t;
typedef struct {
player_t data;
plrcontrol_t ctrl;
AirPlayer *ship;
eplrstats_t stats;
} eplayer_t;
/*
=============================================================================
AIR UNITS
=============================================================================
*/
#define LYR_BOMB 0
#define LYR_UNIT 1
#define LYR_MISS 2
#define LYR_SPRITE 3
#define NUM_LAYERS 4
#define AIRMOVE_DUMB 0
#define AIRMOVE_CHASE 1
#define MAX_ATTACKS 32
#define EW_SHOT 0
#define EW_HOMINGSHOT 1
#define EW_LEFTSHOT 2
#define EW_RIGHTSHOT 3
#define EW_MISSILE 4
#define EW_FIREBALL 5
typedef struct au_attack_s {
int attach;
int type;
float wait;
int repeat;
float delay;
} au_attack_t;
typedef struct airunit_type_s {
struct airunit_type_s **pprev, *next;
int used;
char name[64];
sprite_t *sprite;
bool bBoss;
float flSpeed;
int iMovement;
float flMParm1; // meaning depends on iMovement
float flMParm2;
float flHealth;
int iMoney;
float flAttackCycle; // time between attack sequences
int numattacks;
au_attack_t attacks[MAX_ATTACKS];
int iTrailAttach;
char szTrailSprite[64];
int iTrailTime;
} airunit_type_t;
//
// ge_air.cpp
//
airunit_type_t *Air_GetType(const char *name);
void Air_FreeType(airunit_type_t *type);
class AirBase {
public:
AirBase **m_ppPrev;
AirBase *m_pNext;
bool m_bRemove;
int m_iLayer;
sprite_t *m_pSprite;
int m_iAnimTime;
float m_x, m_y;
float m_lastx, m_lasty;
float m_vel[2];
public:
AirBase(int iLayer, const char *pszSprite, float x, float y);
AirBase(int iLayer, sprite_t *pSprite, float x, float y);
virtual ~AirBase();
virtual void Think();
virtual void Draw();
virtual bool IsGoodGuy() { return false; }
virtual bool IsTangible() { return false; }
virtual bool IsGhost() { return false; }
virtual void Collide(AirBase *pOther) { }
virtual void Damage(AirBase *pInflictor, float flAmt) { }
bool IsInScreen();
void Move(float dx, float dy);
private:
void Init();
};
class AirUnit : public AirBase {
public:
float m_flHealth;
float m_flLowHealth;
int m_iDeathTime;
float m_flDmgExplosions; // explosions per second
float m_flSpeed;
public:
AirUnit(const char *pszSprite, float flSpeed, float x, float y, float health);
AirUnit(sprite_t *sprite, float flSpeed, float x, float y, float health);
virtual void Think();
virtual void Damage(AirBase *pInflictor, float flAmt);
virtual bool IsTangible() { return true; }
virtual void Run() { }
virtual void FinalDeath() { }
virtual void DamageNotice(float amt) { }
public:
int m_iDmgExplosionTimer;
float m_flDeathMoveAngle;
float m_flDeathAngleSpeed;
};
class AirPlayer : public AirUnit {
public:
eplayer_t *m_pPlayer;
int m_iCurWeapon;
int m_iFireMGDelay;
int m_iMGCycle;
int m_iFirePrimaryDelay;
int m_iPrimaryCycle;
bool m_bInFire;
public:
AirPlayer(eplayer_t *pPlayer, float x, float y);
virtual ~AirPlayer();
virtual void Run();
virtual void Draw();
virtual bool IsGoodGuy() { return true; }
virtual void Collide(AirBase *pOther);
bool Input(int code, int c, bool down);
void RunWeapons();
void RunMovement(byte *keystate);
void SelectBestWeapon();
void NextWeapon();
virtual void DamageNotice(float amt);
};
/*
=============================================================================
LEVEL
=============================================================================
*/
#define MAPWIDTH 20
// 640 / 32
struct tiletype_t {
HPicture *pic;
};
class ETileTypes {
public:
unsigned m_iNumTT;
tiletype_t *m_pTT;
public:
ETileTypes();
~ETileTypes();
unsigned Load(const char *name);
inline bool ValidId(unsigned id) { return (id < m_iNumTT); }
};
typedef struct {
unsigned gfx; // ~0 is a NUL tile
} tile_t;
struct jobnode_t {
float dx;
float dy;
};
struct airjob_t {
float x;
float y; // in pixels, 0 = bottom of level
airunit_type_t *type;
byte level; // 0-2
std::vector<jobnode_t> nodes;
public:
airjob_t();
airjob_t(airunit_type_t *ntype);
airjob_t(const airjob_t ©);
~airjob_t();
airjob_t &operator=(const airjob_t ©);
};
struct airsched_t {
float line; // automatically calculated based on shadow
airjob_t *job;
};
typedef std::vector<airjob_t>::iterator airjob_it;
typedef std::vector<airjob_t>::const_iterator airjob_cit;
typedef std::vector<airjob_t*>::iterator airjobp_it;
typedef std::vector<airjob_t*>::const_iterator airjobp_cit;
typedef std::vector<airsched_t>::iterator airsched_it;
typedef std::vector<airsched_t>::const_iterator airsched_cit;
typedef std::vector<jobnode_t>::iterator jobnode_it;
typedef std::vector<jobnode_t>::const_iterator jobnode_cit;
class ELevel {
public:
bool m_bEdit;
int m_iMapLength; // in tiles
ETileTypes *m_pTileTypes;
tile_t *m_pTiles;
float m_flDistance; // scrolling, in tiles
float m_flLastDistance;
public:
int m_iBaseLevel;
char m_szName[32];
char m_szAuthor[32];
int m_iNumBosses; // total # of bosses in the level
public: // air-related stuff
std::vector<airjob_t> m_AirJobs; // list of all airjobs
std::vector<airsched_t> m_AirSched; // list of jobs to dispatch; this is kept sorted backwards
public:
ELevel(ETileTypes *pTileTypes);
~ELevel();
bool Load(const char *fname);
bool Save();
void Clear();
void BeginPlay(int level);
void EndPlay();
void Logic();
void Draw();
void SetEditMode(bool bEdit);
void SetDistance(float dist);
void ScreenToLevel(float sx, float sy, float *plx, float *ply);
void LevelToScreen(float lx, float ly, float *psx, float *psy);
private:
bool SavePrepare();
void LoadAirjobs(LFileRead *fr, unsigned features);
bool LoadTiles(LFileRead *fr);
public: // Tile editing
void TileAtPoint(float x, float y, int *ptx, int *pty);
void PointForTile(int tx, int ty, float *px, float *py);
void Resize(bool start, int tiles);
void SetTile(int x, int y, unsigned id);
unsigned GetTile(int x, int y);
public: // Airjob editing
airjob_t *AddAirJob(airunit_type_t *type, float x, float y);
void AddAirjobs(const std::vector<airjob_t> &jobs, float x, float y);
void DelAirJob(airjob_t *job);
void DelAirjobs(const std::vector<airjob_t*> &jobs);
airjob_t *AirJobAtPoint(float x, float y);
void SetAirjobPos(airjob_t *aj, float x, float y);
bool FindAirJobs(float x1, float y1, float x2, float y2, std::vector<airjob_t*> *list);
airjob_t *NodeAtPoint(float x, float y, int *pidx);
airjob_t *NodeAtPoint(const std::vector<airjob_t*> &list, float x, float y, int *pidx);
};
/*
=============================================================================
GAME ENGINE
=============================================================================
*/
enum {
ge_none,
ge_running,
ge_prewin, // boss destroyed, wait some seconds
ge_abort,
ge_win,
ge_loose
};
#define ENGINE_ABORT 0
#define ENGINE_LOOSE 1
#define ENGINE_WIN 2
class EEngine : public GPanel {
public:
int m_iState;
ELevel *m_pLevel;
eplayer_t m_player;
bool m_bPaused;
int m_iLevel;
int m_iLevelAdjust;
bool m_bEndGame;
public: // ingame variables (valid after Start())
int gametime;
int curframe;
float oldfract, curfract; // interpolation
int m_iBossDestroyed; // # destroyed bosses
int m_iPrewinTime; // win countdown
int m_iFadeoutTime;
public: // difficulty adjustors
float m_flHealthFactor;
int m_iFrameTime; // logic steps (in easy, this is == LOGICTIME)
public:
EEngine();
~EEngine();
const char *MouseCursor();
// setup and post-processing
void SetLevel(ELevel *level, bool edit);
void SetLevelAdjust(int lvl, int adjust);
void PokePlayer(const player_t *player, const LConfig *cfg);
void PeekPlayer(player_t *player);
// runtime
void Begin();
void End();
void Logic();
void Draw();
bool Key(int code, char c, bool down);
void SetPaused(bool paused) { m_bPaused = paused; }
public: // integrated air unit subsystem
AirBase *units_air[NUM_LAYERS];
void Air_Init();
void Air_Shutdown();
void Air_Logic();
void Air_Draw();
void Air_Spawn(airjob_t *aj);
AirBase *Air_FindNearest(float x, float y, bool goodguy, float xdir, float ydir);
public: // integrated HUD subsystem
HPicture *hud_pHealth;
HFont *hud_pFont;
void Hud_Load();
void Hud_Unload();
void Hud_Draw();
};
extern EEngine *ge;
#define LERP(old,cur) ((old)*ge->oldfract + (cur)*ge->curfract)