BASE.H

The base.h file is header file for all classes shared by SPACE_INVADERS and GALAXIANS.
/****************************************************************
    GALVADERS (V1.0), BY AHARON HILLEL.
    gcc version 3.2 (mingw special 20020817-1)
    ALLEGRO VERSION: 4.1.12 (WIP)
    ALLEGRO DATE:    2003-11-10
****************************************************************/
#include <string.h>
#include <baseimage.h>

#include "galvaders.h"
#include "samples.h"

/*  Using STL  */
#include <vector>
#include <list>
using namespace std;
/***********************************************
   PLACE ALL CLASSES THAT ARE USED BY BOTH
   INVADERS AND GLAXIANS IN THIS FILE.
***********************************************/
#if !defined( _BASE_H_ )
#define _BASE_H_
/*  START - Game types  */
struct st_pixel_type
{
    int x;
    int y;
};
typedef struct st_pixel_type st_pixel;

struct st_colors_type
{
    int low_color;
    int high_color;
};
typedef struct st_colors_type st_colors;

struct st_controls_type
{
    unsigned char left;
    unsigned char right;
    unsigned char fire;
};
typedef struct st_controls_type st_controls;

struct st_bullet_params_type
{
    int x_inc;
    int y_inc;

    int x_min;
    int x_max;
    int y_min;
    int y_max;

    st_pixel *hit_pixels;
    int n_hit_pixels;

    st_colors colors;

    int hit_z_order_low;
    int hit_z_order_high;
};
typedef st_bullet_params_type st_bullet_params;

typedef vector<RLE_SPRITE *> images_array;
typedef list<base_image *> sprite_list;

struct st_game_params_type
{   /*  Holds game sprites information.  */
    images_array *images;
    
    /*  Integers to save sprite indexes as saved in the vector.  */
    int aharon_logo;
    int allegro_logo;
    int enemies;
    int g_blast;
    int gal_bullet;
    int gal_players;
    int halftone_gal_players;
    int gal_player_blast;
    int gal_players_small;
    int i_blast;
    int inv_missile;
    int inv_missile_explosion;
    int inv_players;
    int halftone_inv_players;
    int inv_player_blast;
    int inv_players_small;
    int inv_mother_ship;
    int inv_mother_ship_explosion;
    int inv_mother_ship_150;
    int inv_mother_ship_300;
    int inv_player_bullet;
    int gal_player_bullet;
    int shield;
    int gal_bonus_200;
    int gal_bonus_400;
    int gal_bonus_800;
    
    BITMAP *game_logo;
    RGB game_pal[256];
    char *dir;
};
typedef struct st_game_params_type st_game_params;
/*  END   - Game types  */

extern DATAFILE *s_data;
extern st_game_params *game_sprites;
extern class player *player_1;
extern class player *player_2;
extern class inv_formation *invaders;
extern class gal_formation *galaxians;
extern sprite_list explosions_list;
extern sprite_list p_bullets_list;
extern sprite_list e_bullets_list;
extern unsigned int sound_flag;

void init_classes_static_data(unsigned char game_type);

// 0 1 2 3 4 5 6 7   menu_status_register
// | | | | | | | ->  Game-Over         0x80
// | | | | | | --->  VSYNC() on/off    0x40
// | | | | | ----->  Shields on/off    0x20
// | | | | ------->  n-Bullets bit 2   0x10  2 = 4 bullets, 3 = 8 bullets
// | | | --------->  n-Bullets bit 1   0x08  0 = 1 bullets, 1 = 2 bullets
// | | ----------->  Demo Mode         0x04
// | ------------->  Galaxians         0x02  2 = Galaxy game, 3 = Galvaders game
// | ------------->  Invaders          0x01  1 = Invaders game

#define BIT_GAME_OVER         0x80
#define BIT_VSYNC             0x40
#define BIT_SHIELDS           0x20
#define BIT_N_BULLETS_HIGH    0x10
#define BIT_N_BULLETS_LOW     0x08
#define BIT_DEMO_MODE         0x04
#define BIT_GALAXIANS         0x02
#define BIT_INVADERS          0x01

#define SOUND_INVADERS 1
#define SOUND_GALAXY 2
#define SOUND_GALVADERS 3

/*  Place all game Z_ORDER defs here so able to chage in one place    */
/*  Z-ORDER values are not really used in this game since sprites are */
/*  saved in various lists that handled according to list-z-order.    */
#define INVADERS_Z_ORDER 1
#define GALAXY_Z_ORDER   2
#define GALAXY_ATTACK_Z_ORDER   3
#define PLAYER_Z_ORDER   4
#define PLAYER_BULLET_Z_ORDER 5
#define EXPLOSION_Z_ORDER 6

#define TEXT_RIGHT  1
#define TEXT_BOTTOM    1
#define TEXT_CENTER 2
#define TEXT_LEFT   3
#define TEXT_TOP 3

/***  START  *********  recoreding marcors              *******/
/*  Recording will be done only for players.                  */
/*  Each "data record" is contructed of short-int:            */
/*  Bits (high-nibble):                                       */
/*  BIT 13 - player key left. (on/off)                        */
/*  BIT 14 - player key right. (on/off)                       */
/*  BIT 15 - player key fire. (on/off)                        */
/*  BITS 0-12 How many frames the key situation consists      */
/*  from 1-frame to 8191 frames.                              */
/*  The MACROS are used by play_the_game(n) when recording    */
/*  and by player-class when playing a demo.                  */
#define GET_FRAME_COUNTER(S_INT)    (S_INT & 0x1FFF)
#define SET_FRAME_KEYS(KEYS,FRAME,S_INT)  S_INT = (((KEYS & 7) << 13) | (FRAME & 0x1FFF))
#define MAX_PLAYER_DATA 4095

/*  Used by Demo-Mode routines  */
#define BIT_KEY_LEFT  0x2000
#define BIT_KEY_RIGHT 0x4000
#define BIT_KEY_FIRE  0x8000
/***  END    *********  recoreding marcors              *******/

/*  ANIMation values to be used in enemy class.  */
#define ANIM_NONE 0
#define ANIM_LOW_HIGH 1
#define ANIM_HIGH_LOW 2
#define ANIM_PING_PONG 3


/*  Some macors to work with lists  */
#define RUN_LIST_REVERSE(LIST,ITER,FUNC) \
  { \
    if(LIST.size())  /*  if list is NOT empty. */ \
    { \
      ITER = LIST.end(); \
      do{ \
          ITER--; \
          (*ITER)->FUNC(); \
      }while(ITER != LIST.begin()); \
    } \
  }

#define RUN_LIST_INCREMENTAL(LIST,ITER,FUNC) \
  { \
     if(LIST.size())  /*  if list is NOT empty.  */ \
     { \
       ITER = LIST.begin(); \
        while(ITER != LIST.end()) \
        { (*ITER)->FUNC(); ITER++; }; \
     } \
  }

#define RUN_LIST_INCREMENTAL_WITH_REMOVE(LIST,ITER,ITER_REMOVE,FUNC,TEST) \
  {  /*  MACRO to do items action(), then remove dead items or do draw()  */ \
     if(LIST.size())  /*  if list is NOT empty.  */ \
     { \
       ITER = LIST.begin(); \
       while(ITER != LIST.end()) \
       { \
         (*ITER)->FUNC(); \
         ITER_REMOVE = ITER; \
         ITER++; \
         if((*ITER_REMOVE)->TEST() < 0) \
         { /*  Remove a dead item from list  */ \
           delete(*ITER_REMOVE); \
           LIST.erase(ITER_REMOVE); \
         } \
       } /*  End of while loop  */ \
    } \
  }

#define CLEAR_LIST(LIST,ITER,ITER_REMOVE) \
  { \
     if(LIST.size())  /*  if list is NOT empty.  */ \
     { \
       ITER = LIST.begin(); \
       while(ITER != LIST.end()) \
       { \
         ITER_REMOVE = ITER; \
         ITER++; \
         delete(*ITER_REMOVE); \
         LIST.erase(ITER_REMOVE); \
       } /*  End of while loop  */ \
    } \
  }

//---------  START  --  CLASS text_msg  -----------

class text_msg
{
    private:
      BITMAP *dest;
      BITMAP *bg_buffer;
      int background_w;
      int background_h;
      char *text;
      
      unsigned int frames;
      unsigned int blank_frames;
      unsigned int frame_counter;
      
      int show_text;
      int x_pos;
      int y_pos;
      int length;
      char **lines;
      int n_lines;
      char *longest_line;
      int font_type;
      int floating_text;
      int text_color;
      int x_text_orientation; //  Left, Center, Right.
      int y_text_orientation; //  Bottom, Center, top.
      int bg_color;
      BITMAP *bg_tile;        //  Tile-BITMAP private copy is saved in this class.
      
      int get_lines(void);
      void compute_background_size(void);
      
    public:
      text_msg();
      text_msg(BITMAP *dest_bmp);
      text_msg(BITMAP *dest_bmp, char *t, int x, int y, int f, int float_flag, int tc, int bg_c, int txo, int tyo, BITMAP *bg_t, int d);
      text_msg(BITMAP *dest_bmp, char *t, int x, int y, int f, int float_flag, int tc, int bg_c, int txo, int tyo, BITMAP *bg_t, unsigned int f_counter, unsigned int b_frames, int d);
      text_msg(const text_msg &other);
      inline void set_dest_bitmap(BITMAP *bmp) { dest = bmp; };
      void draw(void);
      void remove(void);
      void set_bg_tile(BITMAP *tile);
      inline int get_msg_width(void) {  return background_w; };
      inline int get_msg_height(void) { return background_h; };
      inline void set_blinking_params(int f, int b_frames) { frames = frame_counter = f + b_frames; blank_frames = b_frames; };
      inline void set_font(int new_font) { font_type = new_font; if(bg_buffer) destroy_bitmap(bg_buffer); bg_buffer = NULL; };
      inline void set_text_color(int new_color) { text_color = new_color; };
      inline void set_text_bg_color(int new_color) { bg_color = new_color; };
      inline void set_text_orientation(int new_x_o, int new_y_o) { x_text_orientation = new_x_o; y_text_orientation = new_y_o; };
      inline int get_x_pos(void) { return x_pos; };
      inline int get_y_pos(void) { return y_pos; };
      inline void set_show_text(int flag) { show_text = flag; };
      inline void set_pos(int new_x, int new_y, int d) { x_pos = new_x; y_pos = new_y; if(d) draw(); };
      inline void set_pos_ex(int new_x, int new_y, int new_float_flag, int d);
      inline void set_floating_flag(void) { floating_text = G_TRUE; };
      inline void clear_floating_flag(void) { floating_text = G_FALSE; if(bg_buffer) destroy_bitmap(bg_buffer); bg_buffer = NULL; };
      int set_text(char *new_text);
      ~text_msg(); 
};
//---------  END    --  CLASS text_msg  -----------



int test_hit_pixels(BITMAP *bmp, const st_colors colors, int x, int y, st_pixel *hit_pixels, int n_hit_pixels);
int test_hit_pixels(BITMAP *bmp, const st_colors *colors, const int i_colors, int x, int y, st_pixel *hit_pixels, int n_hit_pixels);

struct st_enemy_params_type
{
      int index_low;
      int index_high;
      int anim_type;

      int x_min;
      int y_min;
      int x_max;
      int y_max;
};
typedef struct st_enemy_params_type st_enemy_params;

class enemy : public base_image
{
    private:
      int index_low;  //  Play animation from between low and high
      int index_high;
      int anim_type;  //  NONE ; LOW->HIGH ; HIGH->LOW ; PING-PONG
      int anim_dir;   //  Init by the value of anim_type

      int x_min;
      int y_min;
      int x_max;
      int y_max;

      static int enemies;

    public:
      enemy();
      enemy(RLE_SPRITE **dt, BITMAP *dst, const int x,  const int y,  const int z, const int bg_f, const int d, const st_enemy_params &p);
      enemy(const enemy &other);     // COPY constructor

      ~enemy();

      int static get_enemies(void) { return enemies; };
      inline void inc_index();
      inline void dec_index();
      inline void switch_anim_dir() { if((anim_type == ANIM_LOW_HIGH) || (anim_type == ANIM_HIGH_LOW)) anim_dir *= -1; };
      inline int get_index_low() { return index_low; };
      inline int get_index_high() { return index_high; };      
      void play_anim(void);
      
      int kill(void);
      int action(void);
};
//---------  END    --  CLASS enemy  -----------

//---------  START  --  CLASS player  -----------
#define PLAYER_BONUSES 4
struct st_player_params_type
{
      st_controls *keys;
      st_pixel *player_hit_pixels;
      int n_player_hit_pixels;

      int fire_sample;
      int exp_sample;
      int bonus_life_sample;
      
      int halftone_sprite_index;
      int bullet_sprite_index;
      int exp_sprite_index_low;
      int exp_sprite_index_high;
      int bullets_max;
      int x_min;
      int x_max;
      int x_inc;
      
      int *player_bonus_scores;
      unsigned short *demo_stream;
};
typedef struct st_player_params_type st_player_params;

class player : public base_image
{
    private:      
      st_controls keys;
      int lives;
      int score;
      int last_score_shown;
      int halftone_counter;
      int bullets;     //  How many shots in the air
      int bullets_max; //  How many shots allowed.
      int start_x;
      int start_y;
      int x_min;
      int x_max;
      
      int fire_sample;
      int exp_sample;
      int bonus_life_sample;
      
      int player_killed_by_enemy;
      st_pixel *player_hit_pixels;
      int n_player_hit_pixels;
      
      int player_sprite_index;
      int halftone_sprite_index;
      int bullet_sprite_index;
      int exp_sprite_index_low;
      int exp_sprite_index_high;      
      int x_bullet_offset;
      int y_bullet_start;
      int shot_fired;
      int x_speed;

      int x_inc;
      int killed;

      class text_msg text_score_header;
      class text_msg text_score;
      class text_msg text_join;
      RLE_SPRITE *player_small_sprite;
      BITMAP *footer_bmp;
      
      unsigned short *demo_stream;
      unsigned short current_frame_counter;
      unsigned int current_demo_index;
      
      int current_bonus_index;
      int player_bonus_scores[PLAYER_BONUSES];
      static int players;
      
      void inc_current_demo_index(void);

    public:
      static st_pixel inv_bullet_hit_pixles[];
      static st_pixel gal_bullet_hit_pixles[];
      static st_pixel inv_player_hit_pixles[];
      static st_pixel gal_player_hit_pixles[];
      
      static st_colors bullet_hit_colors;    
      static st_bullet_params bullet_params;  //  To be used for all player objects.    
      player();
      player(RLE_SPRITE **dt, BITMAP *dst, BITMAP *footer_dst, const int s_index, const int x, const int y, const int z, const int l, const int bg_f, const int d, const st_player_params &p, const int g_font, char *txt_score_h, const int tx_score_h, const int ty_score_h, const int txo_score_h, const int tyo_score_h, char *txt_score, const int tx_score, const int ty_score, const int txo_score, const int tyo_score, char *txt_join, const int tx_join, const int ty_join, const int txo_join, const int tyo_join, const int s_index_small);
      player(const player &other);     // COPY constructor

      ~player();

      int static get_players(void) { return players; };
      void do_fire(void);
      inline int draw(void) { if((lives == 0) || killed) return G_FALSE; if(halftone_counter < 80) if(halftone_counter & 8) return G_FALSE; return base_image::draw(); };

      inline void set_controls(const st_controls &new_controls) { keys = new_controls; };
      inline void inc_bullet_counter(void) { bullets++; };
      inline int get_score(void) { return score; };
      inline void set_score(int value) { score = value; };  //  Used for demo.
      inline int get_lives(void) { return lives; };
      inline int get_player_killed_by_enemy(void) { return player_killed_by_enemy; };
      inline void set_lives(int value) { lives = value; if(lives) text_score_header.set_blinking_params(18,6); else text_score_header.set_blinking_params(0,0); };
      inline void clear_killed_flag(void) { killed = G_FALSE; };
      void update_score(int value);
      inline void set_max_bullets(int value) { bullets_max = value; };

      inline int switch_to_halftone_sprite(int counter) { halftone_counter = counter; set_sprite_index(halftone_sprite_index); };
      inline int switch_to_regular_sprite(void) { set_sprite_index(player_sprite_index); };
      inline void go_to_start_pos(int visible) { set_pos(start_x, start_y, visible); };
      inline void sync_blink_of_score_header(void) { text_score_header.set_blinking_params(18,6); };
      inline int end_of_demo_input(void) { if(!demo_stream) return G_TRUE; return (current_demo_index == demo_stream[0]); };

      int p_test_hit_pixels(void);
      int kill(int more_players_on_field);
      int action(void);
      void remove_player_text(void);
      void draw_player_text(unsigned char game_over);
      void remove_player_lives(void);
      void draw_player_lives(void);
};
//---------  END    --  CLASS player  -----------


//---------  START  --  CLASS bullet  -----------
class bullet : public base_image
{
    private:
      int x_inc;
      int y_inc;

      int x_min;
      int x_max;
      int y_min;
      int y_max;
      
      int score;
      class player *owner;

      st_pixel *hit_pixels;
      int n_hit_pixels;

      st_colors colors;

      int hit_z_order_low;
      int hit_z_order_high;
      
      int test_collision_in_list(sprite_list *list, int sprite_index);

    public:
      bullet();
      bullet(RLE_SPRITE **dt, BITMAP *dst, const int s_index, const int x,  const int y,  const int z, const int bg_f, const int d, const st_bullet_params &p);
      bullet(RLE_SPRITE **dt, BITMAP *dst, class player *p_owner, const int s_index, const int x,  const int y,  const int z, const int bg_f, const int d, const st_bullet_params &p);      
      bullet(const bullet &other);     // COPY constructor

      ~bullet();

      int action(void);
};
//---------  END    --  CLASS bullet  -----------

//---------  START  --  CLASS explosion  --------
class explosion : public base_image
{
    private:
      int center_x;
      int center_y;
      unsigned int speed;      // how many frames for each move.
      unsigned int frame_cnt;  // counter when = 0, next move.
      int index_low;
      int index_high;

    public:
      explosion();
      explosion(RLE_SPRITE **dt, BITMAP *dst, const int i_low, const int i_high, const int x, const int y, const int z, const unsigned int f_speed, const int bg_f, const int d);
      explosion(const explosion &other);     // COPY constructor

      ~explosion();

      int explosion::action(void);
};
//---------  END    --  CLASS explosion  --------


//---------  START  --  CLASS formation  --------
struct st_formation_move_type
{
    int x_inc;
    int y_inc;
    int times;
    int int_to_next_move;
};
typedef struct st_formation_move_type st_formation_move;

#define ITEM_IS_DEAD 0
#define ITEM_IN_FORMATION 1
#define ITEM_IN_ATTACK 2
struct st_item_type
{
    int x;
    int y;
    int sample;
    int score;
    class enemy *sprite;
    int state;
};
typedef struct st_item_type st_item;


struct st_formation_param_type
{
    BITMAP *buffer; //  On what BITMAP formation will be drawn.
    st_item *list;  //  To be deleted in formation destructor

    int x_left_border;
    int x_right_border;
    int y_top_border;
    int y_bottom_border;
    
    unsigned int frame_rate;
    int rows;
    int cols;

    st_formation_move *moves;  //  To be deleted in formation destructor
};
typedef struct st_formation_param_type st_formation_param;

class formation
{
    private:
      BITMAP *buffer;
      int counter;
      st_item *items;
      int live_items;

      int x_left_border;
      int x_right_border;
      int y_top_border;
      int y_bottom_border;

      int rows;
      int cols;

      unsigned int frame_rate;
      unsigned int frame_counter;

      st_formation_move *moves;
      int current_move;
      int move_count;

      void move_formation_right();
      void move_formation_left();
      void move_formation_up();
      void move_formation_down();

protected:
      int test_formation_left();
      int test_formation_right();
      int test_formation_top();
      int test_formation_bottom();
      static int attack_ok;

    public:
      formation();
      formation(const st_formation_param &p);
      ~formation();
      
      inline int get_cols(void) { return cols; };
      inline int get_rows(void) { return rows; };
      inline int get_counter(void) { return counter; };
      inline int get_live_items(void) { return live_items; };
      inline unsigned int get_frame_rate(void) { return frame_rate; };
      inline int set_frame_rate(unsigned int value) { frame_rate = value; };
      inline static int get_attack_ok(void) { return attack_ok; };
      inline static void set_attack_ok(void) { attack_ok = G_TRUE; };
      inline static void clear_attack_ok(void) { attack_ok = G_FALSE; };
      void remove(void);
      void draw();
      inline st_item *get_item(int c, int r) { return &items[r]+(c * cols); };
      inline BITMAP *get_dest_bitmap(void) { return buffer; };
      int test_formation_for_hit(int x_pos, int y_pos, int bullet_index, int e_index_low, int e_index_high, unsigned int do_sound);
      void get_fire_options(st_pixel *opt, int max_col, int *n_opt);
      void action();
};
//---------  END    --  CLASS formation  --------


#define GAME_HEADER_LINE1_Y 0
#define GAME_HEADER_LINE2_Y 19
#define GAME_HEADER_BORDER_LINE 42
#define GAME_FOOTER_BORDER_LINE 455

#endif // _BASE_H_