/****************************************************************
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 "base.h"
#include "inv.h"
/***********************************************
PLACE ALL CLASSES THAT ARE USED BY BOTH
INVADERS AND GLAXIANS IN THIS FILE.
***********************************************/
//--------- START -- CLASSes STATIC init --------
int enemy::enemies = 0;
int player::players = 0;
st_bullet_params player::bullet_params = { 0 }; // Will be initialized b4 game starts.
st_pixel player::inv_bullet_hit_pixles[] = { 0,0 ,3,0, 0,6, 3,6, 0,11, 3,11 };
st_pixel player::gal_bullet_hit_pixles[] = { 2,0, 0,3, 4,3, 1,9, 3,9 };
st_pixel player::inv_player_hit_pixles[] = { 16,0, 19,0, 3,14, 32,14, 0,19, 35,19 };
st_pixel player::gal_player_hit_pixles[] = { 17,0, 5,19, 29,19, 0,23, 34,23, 0,30, 34,30 };
st_colors player::bullet_hit_colors = { 13, 67 };
int formation::attack_ok = 0;
//--------- END -- CLASSes STATIC init --------
text_msg::text_msg()
{
dest = NULL;
text = NULL;
bg_tile = NULL;
bg_buffer = NULL;
lines = NULL;
longest_line = NULL;
show_text = G_TRUE;
x_pos = y_pos = length = font_type = floating_text = text_color = bg_color = n_lines = background_w = background_h = frames = blank_frames = frame_counter = 0;
x_text_orientation = TEXT_LEFT; // Left, Center, Right.
y_text_orientation = TEXT_BOTTOM; // Bottom, Center, Top.
}
text_msg::text_msg(BITMAP *dest_bmp)
{
dest = dest_bmp;
text = NULL;
bg_tile = NULL;
bg_buffer = NULL;
lines = NULL;
longest_line = NULL;
show_text = G_TRUE;
x_pos = y_pos = length = font_type = floating_text = text_color = bg_color = n_lines = background_w = background_h = frames = blank_frames = frame_counter = 0;
x_text_orientation = TEXT_LEFT; // Left, Center, Right.
y_text_orientation = TEXT_BOTTOM; // Bottom, Center, Top.
}
text_msg::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 = NULL;
dest = dest_bmp;
show_text = G_TRUE;
x_pos = x; y_pos = y; font_type = f;
floating_text = float_flag;
text_color = tc; bg_color = bg_c;
x_text_orientation = txo; y_text_orientation = tyo;
frames = blank_frames = frame_counter = 0;
bg_tile = NULL;
bg_buffer = NULL;
length = strlen(t);
if(!length)
return;
if(bg_t)
{ // save a copy of the tile.
bg_tile = create_bitmap(bg_t->w, bg_t->h);
blit(bg_t, bg_tile, 0, 0, 0, 0, bg_t->w, bg_t->h);
}
text = (char *) malloc(length + 1);
strcpy(text, t);
get_lines();
compute_background_size();
if(d)
draw();
}
text_msg::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 = NULL;
dest = dest_bmp;
show_text = G_TRUE;
frames = frame_counter = f_counter + b_frames;
blank_frames = b_frames;
x_pos = x; y_pos = y; font_type = f;
floating_text = float_flag;
text_color = tc; bg_color = bg_c;
x_text_orientation = txo; y_text_orientation = tyo;
bg_tile = NULL;
bg_buffer = NULL;
length = strlen(t);
if(!length)
return;
if(bg_t)
{ // save a copy of the tile.
bg_tile = create_bitmap(bg_t->w, bg_t->h);
blit(bg_t, bg_tile, 0, 0, 0, 0, bg_t->w, bg_t->h);
}
text = (char *) malloc(length + 1);
strcpy(text, t);
get_lines();
compute_background_size();
if(d)
draw();
}
text_msg::text_msg(const text_msg &other)
{
text = NULL;
dest = other.dest;
show_text = other.show_text;
frames = other.frames;
frame_counter = other.frame_counter;
blank_frames = other.blank_frames;
x_pos = other.x_pos;
y_pos = other.y_pos;
font_type = other.font_type;
floating_text = other.floating_text;
text_color = other.text_color;
bg_color = other.bg_color;
x_text_orientation = other.x_text_orientation;
y_text_orientation = other.y_text_orientation;
bg_tile = NULL;
bg_buffer = NULL;
length = other.length;
background_w = other.background_w;
background_h = other.background_h;
if(!length)
return;
if(other.bg_tile)
{ // save a copy of the tile.
bg_tile = create_bitmap(other.bg_tile->w, other.bg_tile->h);
blit(other.bg_tile, bg_tile, 0, 0, 0, 0, other.bg_tile->w, other.bg_tile->h);
}
text = (char *) malloc(length + 1);
strcpy(text, other.text);
get_lines();
}
int text_msg::get_lines(void)
{
int i;
int temp = 0;
char *p = text;
n_lines = 1;
longest_line = text;
for(i = 0; i < length; i++)
if((text[i]) == '\n')
{
text[i] = '\0';
/*
if(strlen(longest_line) < strlen(p))
longest_line = p;
*/
/* Compute length in pixels instead because sometimes same-length strings have different size in graphics */
if(text_length((FONT *) s_data[font_type].dat, longest_line) < text_length((FONT *) s_data[font_type].dat, p))
longest_line = p;
p = &text[i+1];
n_lines++;
}
lines = (char **) malloc(n_lines * sizeof(char *));
temp = 0;
lines[temp] = text;
for(i = 0; i < length; i++)
{ // Save line pointers in lines array.
if(text[i] == '\0')
{
temp++;
lines[temp] = &(text[i+1]);
}
}
}
void text_msg::compute_background_size(void)
{
background_w = background_h = 0;
if(!text)
return;
if(!dest)
return;
int t_ht = text_height((FONT *) s_data[font_type].dat);
if(bg_tile)
{ // Compute background rect according to tile size.
int t_width = text_length((FONT *) s_data[font_type].dat, longest_line);
int tiles = t_width / bg_tile->w;
if(t_width % bg_tile->w)
tiles++;
background_w = tiles * bg_tile->w;
tiles = (n_lines * t_ht) / bg_tile->h;
if((n_lines * t_ht) % bg_tile->h)
tiles++;
background_h = tiles * bg_tile->h;
}
else
{ // Compute background rect according to text size.
background_w = text_length((FONT *) s_data[font_type].dat, longest_line);
background_h = n_lines * t_ht;
}
}
void text_msg::set_bg_tile(BITMAP *tile)
{
if(bg_tile)
destroy_bitmap(bg_tile);
bg_tile = NULL;
if(tile)
{ // save a copy of the tile.
bg_tile = create_bitmap(tile->w, tile->h);
blit(tile, bg_tile, 0, 0, 0, 0, tile->w, tile->h);
/* Tile size may change so compute background size. */
compute_background_size();
}
}
void text_msg::draw(void)
{
if(!text)
return;
if(!dest)
return;
int text_bk_color = bg_color;
int t_ht = text_height((FONT *) s_data[font_type].dat);
int o_x_pos = x_pos; // Assume Right orientation.
int o_y_pos = y_pos; // Assume Bottom orientation.
if(x_text_orientation == TEXT_CENTER)
o_x_pos -= background_w >> 1;
if(x_text_orientation == TEXT_LEFT)
o_x_pos -= background_w;
if(y_text_orientation == TEXT_CENTER)
o_y_pos -= background_h >> 1;
if(y_text_orientation == TEXT_TOP)
o_y_pos -= background_h;
if(floating_text)
{ // Save background first.
if(bg_buffer)
if((background_w != bg_buffer->w) || (background_h != bg_buffer->h))
{
destroy_bitmap(bg_buffer);
bg_buffer = NULL;
}
if(!bg_buffer)
bg_buffer = create_bitmap(background_w, background_h);
blit(dest, bg_buffer, o_x_pos, o_y_pos, 0, 0, background_w, background_h);
}
if(bg_tile)
{ // First blit tile, then do the text.
text_bk_color = -1;
int ht; int wd;
for(ht = 0; ht < background_h; ht += bg_tile->h)
for(wd = 0; wd < background_w; wd += bg_tile->w)
blit(bg_tile, dest, 0, 0, o_x_pos+wd, o_y_pos+ht, bg_tile->w, bg_tile->h);
}
// Write text.
int show_text_flag = G_TRUE;
if(frames) // if this text sould blink.
{
if(frame_counter)
{
frame_counter--;
if(frame_counter <= blank_frames)
show_text_flag = G_FALSE;
}
else
frame_counter = frames;
}
if(show_text & show_text_flag)
for(int i = 0; i < n_lines; i++)
textout_ex(dest, (FONT *) s_data[font_type].dat, lines[i], o_x_pos, o_y_pos+(i*t_ht), text_color, text_bk_color);
}
void text_msg::remove()
{
if(!text)
return;
if(!dest)
return;
int o_x_pos = x_pos; // Assume Right orientation.
int o_y_pos = y_pos; // Assume Bottom orientation.
if(x_text_orientation == TEXT_CENTER)
o_x_pos -= background_w >> 1;
if(x_text_orientation == TEXT_LEFT)
o_x_pos -= background_w;
if(y_text_orientation == TEXT_CENTER)
o_y_pos -= background_h >> 1;
if(y_text_orientation == TEXT_TOP)
o_y_pos -= background_h;
if(bg_buffer) // Restore background.
blit(bg_buffer, dest, 0, 0, o_x_pos, o_y_pos, bg_buffer->w, bg_buffer->h);
else // Fill a black rectangle.
rectfill(dest, o_x_pos, o_y_pos, o_x_pos+background_w, o_y_pos+background_h, 0);
}
inline void text_msg::set_pos_ex(int new_x, int new_y, int new_float_flag, int d)
{
x_pos = new_x;
y_pos = new_y;
if(!new_float_flag)
if(bg_buffer)
{
destroy_bitmap(bg_buffer);
bg_buffer = NULL;
}
if(d)
draw();
}
int text_msg::set_text(char *new_text)
{ /* Returns length of text that was set */
if(lines)
free(lines);
lines = NULL;
if(!new_text)
{ // Clear this string.
if(text)
free(text);
text = NULL;
return 0;
}
if(strlen(new_text) != length)
{ // Allocate new length string.
if(text)
free(text);
text = NULL;
length = strlen(new_text);
if(!length)
return length;
text = (char *) malloc(length+1);
}
strcpy(text, new_text);
get_lines();
compute_background_size();
return length;
}
text_msg::~text_msg()
{
if(bg_buffer)
destroy_bitmap(bg_buffer);
if(bg_tile)
destroy_bitmap(bg_tile);
if(text)
free(text);
if(lines)
free(lines);
}
//--------- 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 i;
int c;
if(!bmp)
return 0;
for(i = 0; i < n_hit_pixels ; i++)
{
//c = getpixel(bmp, x + hit_pixels[i].x,y + hit_pixels[i].y);
c = bmp->line[y + hit_pixels[i].y][x + hit_pixels[i].x];
if(c >= colors.low_color && c <= colors.high_color)
return c;
}
return 0;
}
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)
{ /* Same as test_hit_pixels but test against a list of colors-rages. Not used in this game */
int i;
int j;
int c;
if(!bmp)
return 0;
for(i = 0; i < n_hit_pixels ; i++)
for (j = 0 ; j < i_colors; j++)
{
//c = getpixel(bmp, x + hit_pixels[i].x,y + hit_pixels[i].y);
c = bmp->line[y + hit_pixels[i].y][x + hit_pixels[i].x];
if(c >= colors[j].low_color && c <= colors[j].high_color)
return c;
}
return 0;
}
//--------- START -- CLASS enemy -----------
enemy::enemy() : base_image()
{ // Cannot be used.
anim_type = ANIM_NONE;
anim_dir = 0;
enemies++;
};
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) : base_image(dt, dst, x, y, z, p.index_low, bg_f, d)
{
enemies++;
// Init all private members from struct.
index_low = p.index_low;
index_high = p.index_high;
anim_type = p.anim_type;
switch(anim_type)
{
case ANIM_LOW_HIGH:
case ANIM_PING_PONG:
anim_dir = 1;
break;
case ANIM_HIGH_LOW:
anim_dir = -1;
break;
default:
anim_dir = 0;
};
x_min = p.x_min;
y_min = p.y_min;
x_max = p.x_max;
y_max = p. y_max;
};
enemy::enemy(const enemy &other)
{ // COPY constructor
enemies++;
index_low = other.index_low;
index_high = other.index_high;
anim_type = other.anim_type;
anim_dir = other.anim_dir;
x_min = other.x_min;
y_min = other.y_min;
x_max = other.x_max;
y_max = other. y_max;
};
enemy::~enemy()
{
enemies--;
};
inline void enemy::inc_index(void)
{
if(get_sprite_index() < index_high)
set_sprite_index(get_sprite_index() + 1);
};
inline void enemy::dec_index(void)
{
if(get_sprite_index() > index_low)
set_sprite_index(get_sprite_index() - 1);
};
void enemy::play_anim(void)
{
if(anim_type == ANIM_NONE)
return;
int t_index = get_sprite_index();
t_index += anim_dir;
if((t_index < index_low) || (t_index > index_high))
{
switch(anim_type)
{
case ANIM_LOW_HIGH:
set_sprite_index(index_low);
break;
case ANIM_HIGH_LOW:
set_sprite_index(index_high);
break;
case ANIM_PING_PONG:
anim_dir *= -1;
set_sprite_index(get_sprite_index() + anim_dir);
break;
}
}
else
set_sprite_index(t_index);
};
int enemy::kill(void)
{
return G_TRUE;
}
int enemy::action(void)
{
return G_TRUE;
}
//--------- END -- CLASS enemy -----------
//--------- START -- CLASS bullet -----------
bullet::bullet() : base_image()
{ // This cannot be used.
hit_z_order_low = hit_z_order_high = -1; // invalid speed.
score = 0;
owner = NULL;
};
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) : base_image(dt, dst, x, y, z, s_index, bg_f, d)
{
x_inc = p.x_inc;
y_inc = p.y_inc;
x_min = p.x_min;
x_max = p.x_max;
y_min = p.y_min;
y_max = p.y_max;
owner = NULL;
score = 0;
hit_pixels = p.hit_pixels;
n_hit_pixels = p.n_hit_pixels;
colors = p.colors;
hit_z_order_low = p.hit_z_order_low;
hit_z_order_high = hit_z_order_high;
};
bullet::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) : base_image(dt, dst, x, y, z, s_index, bg_f, d)
{
x_inc = p.x_inc;
y_inc = p.y_inc;
x_min = p.x_min;
x_max = p.x_max;
y_min = p.y_min;
y_max = p.y_max;
owner = p_owner; // May be a NULL pointer if no-owner (enemy bullet)
score = 0;
hit_pixels = p.hit_pixels;
n_hit_pixels = p.n_hit_pixels;
colors = p.colors;
hit_z_order_low = p.hit_z_order_low;
hit_z_order_high = hit_z_order_high;
if(owner)
owner->inc_bullet_counter();
};
bullet::bullet(const bullet &other) // COPY constructor
{
x_inc = other.x_inc;
y_inc = other.y_inc;
x_min = other.x_min;
x_max = other.x_max;
y_min = other.y_min;
y_max = other.y_max;
owner = NULL; // Will not share owner.
score = 0;
hit_pixels = other.hit_pixels;
n_hit_pixels = other.n_hit_pixels;
colors = other.colors;
hit_z_order_low = other.hit_z_order_low;
hit_z_order_high = other.hit_z_order_high;
};
bullet::~bullet()
{
if(owner) // Tell owner bullet-out-of-scoop.
owner->update_score(score);
};
int bullet::test_collision_in_list(sprite_list *list, int sprite_index)
{
if((*list).size()) /* if list is NOT empty. */
{
sprite_list::iterator iter;
iter = (*list).begin();
do{
if((*iter)->get_sprite_index() == sprite_index)
if((collision((*iter)->get_x_pos(), (*iter)->get_y_pos(), *(*game_sprites->images)[sprite_index])))
{
if((*iter)->get_sprite_index() == ((*game_sprites).inv_missile))
{ // Make explosion for Invaders bullets only.
class explosion *e = new explosion(&(*game_sprites->images)[0], (*iter)->get_dest_bitmap(), (*game_sprites).inv_missile_explosion, (*game_sprites).inv_missile_explosion, (*iter)->get_x_pos()+(((*game_sprites->images)[sprite_index])->w >> 1), (*iter)->get_y_pos()+(((*game_sprites->images)[sprite_index])->h >> 1), EXPLOSION_Z_ORDER, 8, G_TRUE, G_FALSE);
if(e)
explosions_list.push_back(e);
}
(*iter)->set_sprite_index(-1); // Will be removed later.
return G_TRUE;
}
iter++;
}while(iter != (*list).end());
}
return G_FALSE;
}
int bullet::action(void)
{
int x = get_x_pos();
int y = get_y_pos();
int s_index = get_sprite_index();
int hit;
if(s_index < 0)
return G_FALSE;
/* Test for hit */
hit = test_hit_pixels(get_background_bitmap(), colors, 0, 0, hit_pixels, n_hit_pixels);
if(hit)
{
if((hit >= 13) && (hit <=15))
{ // Bullet hit shield. Damage shield.
rectfill(get_dest_bitmap(), x-3, y-3, x+3+((*game_sprites->images)[s_index])->w, y+3+((*game_sprites->images)[s_index])->h, 0);
if(s_index == ((*game_sprites).inv_missile))
{ // Make explosion for Invaders bullets only.
class explosion *e = new explosion(&(*game_sprites->images)[0], get_dest_bitmap(), (*game_sprites).inv_missile_explosion, (*game_sprites).inv_missile_explosion, x+(((*game_sprites->images)[s_index])->w >> 1), y+(((*game_sprites->images)[s_index])->h >> 1), EXPLOSION_Z_ORDER, 8, G_TRUE, G_FALSE);
if(e)
explosions_list.push_back(e);
}
set_sprite_index(-1);
return G_TRUE;
}
if((hit >= 65) && (hit <=67))
if(test_collision_in_list(&e_bullets_list, (*game_sprites).inv_missile))
{ // Bullet hit invader missile.
set_sprite_index(-1);
return G_TRUE;
}
if(invaders)
{
if((hit >= 16) && (hit <= 45))
score = ((formation *) invaders)->test_formation_for_hit(x, y, s_index, (*game_sprites).i_blast, (*game_sprites).i_blast+2, sound_flag & SOUND_INVADERS);
if((hit >= 32) && (hit <= 34))
{
RLE_SPRITE *bullet_sprite = (*game_sprites->images)[s_index];
score = invaders->destroy_mother_ship(x + ((bullet_sprite->w) >> 1));
}
}
if(galaxians)
{
if((hit >= 46) && (hit <=64))
score = ((formation *) galaxians)->test_formation_for_hit(x, y, s_index, (*game_sprites).g_blast, (*game_sprites).g_blast+2, sound_flag & SOUND_GALAXY);
}
if((hit >= 1) && (hit <= 12))
{ // Kill player...
if(hit < 7)
player_1->kill(player_2->get_lives());
else
player_2->kill(player_1->get_lives());
}
set_sprite_index(-1);
return G_TRUE;
}
x += x_inc;
y += y_inc;
if(x > x_max)
set_sprite_index(-1);
if(x < x_min)
set_sprite_index(-1);
if(y > y_max)
set_sprite_index(-1);
if(y < y_min)
set_sprite_index(-1);
if(get_sprite_index() == -1) // Bullet hit ground. explosion - invaders only.
if(s_index == ((*game_sprites).inv_missile))
{ // Make explosion for Invaders bullets only.
class explosion *e = new explosion(&(*game_sprites->images)[0], get_dest_bitmap(), (*game_sprites).inv_missile_explosion, (*game_sprites).inv_missile_explosion, x+(((*game_sprites->images)[s_index])->w >> 1), y+(((*game_sprites->images)[s_index])->h >> 1), EXPLOSION_Z_ORDER, 8, G_TRUE, G_FALSE);
if(e)
explosions_list.push_back(e);
}
set_pos(x, y, G_FALSE);
return G_TRUE;
};
//--------- END -- CLASS bullet -----------
//--------- START -- CLASS player -----------
player::player() : base_image()
{ // This cannot be used.
footer_bmp = NULL;
player_small_sprite = NULL;
player_hit_pixels = NULL;
demo_stream = NULL;
n_player_hit_pixels = player_killed_by_enemy = 0;
lives = score = bullets = killed = halftone_counter = last_score_shown = 0;
player_sprite_index = halftone_sprite_index = -1;
players++;
current_bonus_index = current_demo_index = current_frame_counter = 0;
memset(player_bonus_scores, 0, PLAYER_BONUSES * sizeof(int));
};
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) : base_image(dt, dst, x, y, z, s_index, bg_f, d), text_score_header(dst, txt_score_h, tx_score_h, ty_score_h, g_font, G_TRUE, 246, -1, txo_score_h, tyo_score_h, NULL, G_FALSE), text_score(dst, txt_score, tx_score, ty_score, g_font, G_TRUE, 215, -1, txo_score, tyo_score, NULL, G_FALSE), text_join(footer_dst, txt_join, tx_join, ty_join, g_font, G_FALSE, 251, -1, txo_join, tyo_join, NULL, 18, 6, G_FALSE)
{
players++;
lives = l;
footer_bmp = footer_dst;
player_small_sprite = (*game_sprites->images)[s_index_small];
score = bullets = killed = last_score_shown = player_killed_by_enemy = 0;
start_x = x;
start_y = y;
score = bullets = halftone_counter = 0;
shot_fired = G_FALSE;
bullets_max = p.bullets_max;
bullet_sprite_index = p.bullet_sprite_index;
exp_sprite_index_low = p.exp_sprite_index_low;
exp_sprite_index_high = p.exp_sprite_index_high;
player_sprite_index = s_index;
halftone_sprite_index = p.halftone_sprite_index;
fire_sample = p.fire_sample;
exp_sample = p.exp_sample;
bonus_life_sample = p.bonus_life_sample;
keys = *p.keys;
x_min = p.x_min;
x_max = p.x_max;
player_hit_pixels = p.player_hit_pixels;
n_player_hit_pixels = p.n_player_hit_pixels;
x_inc = x_speed = p.x_inc;
x_bullet_offset = (dt[s_index]->w >> 1) - ((dt[bullet_sprite_index]->w) >> 1);
y_bullet_start = y; // - dt[bullet_sprite_index]->h;
current_demo_index = current_frame_counter = 0;
demo_stream = NULL;
if(p.demo_stream)
{ // We are running in DEMO_MODE
demo_stream = (unsigned short *) malloc(p.demo_stream[0] * sizeof(unsigned short));
if(demo_stream)
{ // We are running in DEMO_MODE
memcpy(demo_stream, p.demo_stream, p.demo_stream[0] * sizeof(unsigned short));
current_demo_index = 1;
current_frame_counter = GET_FRAME_COUNTER(demo_stream[current_demo_index]);
}
}
current_bonus_index = 0;
memcpy(player_bonus_scores, p.player_bonus_scores, PLAYER_BONUSES * sizeof(int));
if(lives)
text_score_header.set_blinking_params(27,9);
};
player::player(const player &other) // COPY constructor
{
players++;
score = other.score;
last_score_shown = other.last_score_shown;
bullets = 0; // Do not inherit other player bullets.
bullets_max = other.bullets_max;
killed = other.killed;
lives = other.lives;
footer_bmp = other.footer_bmp;
fire_sample = other.fire_sample;
exp_sample = other.exp_sample;
bonus_life_sample = other.bonus_life_sample;
player_killed_by_enemy = other.player_killed_by_enemy;
halftone_counter = other.halftone_counter;
start_x = other.start_x;
start_y = other.start_y;
player_hit_pixels = other.player_hit_pixels;
n_player_hit_pixels = other.n_player_hit_pixels;
shot_fired = other.shot_fired;
bullet_sprite_index = other.bullet_sprite_index;
exp_sprite_index_low = other.exp_sprite_index_low;
exp_sprite_index_high = other.exp_sprite_index_high;
x_bullet_offset = other.x_bullet_offset;
y_bullet_start = other.y_bullet_start;
player_sprite_index = other.player_sprite_index;
halftone_sprite_index = other.halftone_sprite_index;
keys = other.keys;
x_min = other.x_min;
x_max = other.x_max;
x_speed = other.x_speed;
x_inc = other.x_inc;
bullet_params = other.bullet_params;
text_score_header = other.text_score_header;
text_score = other.text_score;
text_join = other.text_join;
player_small_sprite = other.player_small_sprite;
current_bonus_index = other.current_bonus_index;
memcpy(player_bonus_scores, other.player_bonus_scores, PLAYER_BONUSES * sizeof(int));
current_demo_index = other.current_demo_index;
current_frame_counter = other.current_frame_counter;
demo_stream = NULL;
if(other.demo_stream)
{ // We are running in DEMO_MODE
demo_stream = (unsigned short *) malloc(other.demo_stream[0] * sizeof(unsigned short));
if(demo_stream)
memcpy(demo_stream, other.demo_stream, other.demo_stream[0] * sizeof(unsigned short));
}
};
player::~player()
{
if(demo_stream)
free(demo_stream);
players--;
};
void player::do_fire(void)
{
if(formation::get_attack_ok())
{
class bullet *p = new bullet(&(*game_sprites->images)[0], get_dest_bitmap(), this, bullet_sprite_index, get_x_pos()+x_bullet_offset, y_bullet_start, PLAYER_BULLET_Z_ORDER, G_TRUE, G_FALSE, bullet_params);
if(p)
{
shot_fired = G_TRUE;
p_bullets_list.push_back(p);
if(sound_flag)
play_sample((SAMPLE *) s_data[fire_sample].dat, 255, 128, 1000, 0);
}
}
};
void player::update_score(int value)
{
bullets--;
score += value;
if(score >= 1000000)
score -= 1000000;
if(current_bonus_index < PLAYER_BONUSES)
if(score >= player_bonus_scores[current_bonus_index])
{
lives++;
draw_player_lives();
current_bonus_index++;
if(sound_flag)
play_sample((SAMPLE *) s_data[bonus_life_sample].dat, 224, 128, 1000, 0);
}
}
int player::p_test_hit_pixels(void)
{
if(killed) // Don't check if new player not on field yet.
return 0;
player_killed_by_enemy = 0;
if(halftone_counter) // No test in halftone mode. (cannot be hit).
return 0;
player_killed_by_enemy = test_hit_pixels(get_dest_bitmap(), bullet_hit_colors, get_x_pos(), get_y_pos(), player_hit_pixels, n_player_hit_pixels);
return 0;
}
int player::kill(int more_players_on_field)
{
if(killed) // Cannot do the kill twice.
return G_FALSE;
killed = G_TRUE;
int s_index = get_sprite_index();
if((s_index < 0) || (lives == 0))
return G_FALSE;
lives--;
if(!lives)
text_score_header.set_blinking_params(0,0);
class explosion *e = new explosion(&(*game_sprites->images)[0], get_dest_bitmap(), exp_sprite_index_low, exp_sprite_index_high, get_x_pos()+(((*game_sprites->images)[s_index])->w >> 1), get_y_pos()+(((*game_sprites->images)[s_index])->h >> 1), EXPLOSION_Z_ORDER, 5, G_TRUE, G_FALSE);
if(e)
explosions_list.push_back(e);
if(sound_flag)
play_sample((SAMPLE *) s_data[exp_sample].dat, 255, 128, 1000, 0);
if(player_killed_by_enemy)
{ // Test which enemy killed player.
int hit_score = ((formation *) galaxians)->test_formation_for_hit(get_x_pos(), get_y_pos(), s_index, (*game_sprites).g_blast, (*game_sprites).g_blast+2, sound_flag & SOUND_GALAXY);
score += hit_score;
player_killed_by_enemy = 0; // Reset flag.
}
go_to_start_pos(G_FALSE);
if(more_players_on_field) // Immidiate recover as halftone.
switch_to_halftone_sprite(250);
else
formation::clear_attack_ok();
};
void player::inc_current_demo_index(void)
{
if(current_frame_counter)
{
current_frame_counter--;
return;
}
current_demo_index++;
if(end_of_demo_input())
return;
current_frame_counter = GET_FRAME_COUNTER(demo_stream[current_demo_index]);
}
int player::action(void)
{
// allegro_message("index = <%d> killed = <%d lives = <%d", get_sprite_index(),killed,lives);
if((get_sprite_index() < 0) || (lives == 0))
return G_FALSE;
if(halftone_counter)
{
halftone_counter--;
if(halftone_counter > 200)
return G_TRUE; // Player still invisible after kill.
remove_player_lives(); // Update screen when bringing-up new player.
killed = G_FALSE; // From now on halftone player is visible/active.
draw_player_lives();
if(!halftone_counter) // Finished halftone-time
return switch_to_regular_sprite();
}
if(killed)
return G_TRUE;
int fire;
int x = get_x_pos();
if(demo_stream)
{ // We are running in DEMO_MODE. Get input from demo stream.
if(end_of_demo_input())
return G_TRUE;
fire = demo_stream[current_demo_index] & BIT_KEY_FIRE;
if(demo_stream[current_demo_index] & BIT_KEY_LEFT)
if(x > x_min)
x -= x_inc;
if(demo_stream[current_demo_index] & BIT_KEY_RIGHT)
if(x < x_max)
x += x_inc;
inc_current_demo_index();
}
else
{ // Get input from player controls.
fire = key[keys.fire];
if(key[keys.left])
if(x > x_min)
x -= x_inc;
if(key[keys.right])
if(x < x_max)
x += x_inc;
}
if(fire)
{
if(!shot_fired)
if(bullets < bullets_max)
do_fire();
}
else shot_fired = G_FALSE;
if(x < x_min)
x = x_min;
if(x > x_max)
x = x_max;
set_pos(x,get_y_pos(), G_FALSE);
};
void player::remove_player_text(void)
{
text_score_header.remove();
text_score.remove();
if((lives == 0) || demo_stream)
text_join.remove();
};
void player::draw_player_text(unsigned char game_over)
{
if(last_score_shown != score)
{ // a bit optimization.
char text[7];
char t_score[7];
last_score_shown = score;
memset(text, '0', 7);
sprintf(t_score,"%d", score);
strcpy((text+6)-strlen(t_score), t_score);
text_score.set_text(text);
}
text_score_header.draw();
text_score.draw();
if((lives == 0 && (!game_over)) || demo_stream)
text_join.draw(); // Show join-text if game is not over.
};
void player::remove_player_lives(void)
{
if(demo_stream)
return; // We don't draw them in Demo-mode
int small_x_pos = 0;
int x_inc = player_small_sprite->w+2;
int small_y_pos = (footer_bmp->h) - (player_small_sprite->h);
int i;
if(start_x)
{ // Go from left to right.
small_x_pos = SCREEN_W - (player_small_sprite->w);
x_inc = -(player_small_sprite->w+2);
}
for(i = 0; i < lives; i++)
{
rectfill(footer_bmp, small_x_pos, small_y_pos, small_x_pos+(player_small_sprite->w), small_y_pos+(player_small_sprite->h), 0);
small_x_pos += x_inc;
}
}
void player::draw_player_lives(void)
{
if(demo_stream)
return; // We don't draw them in Demo-mode
int small_x_pos = 0;
int x_inc = player_small_sprite->w+2;
int small_y_pos = (footer_bmp->h) - (player_small_sprite->h);
int i;
if(start_x)
{ // Go from left to right.
small_x_pos = SCREEN_W - (player_small_sprite->w);
x_inc = -(player_small_sprite->w+2);
}
for(i = 0; i < lives-1; i++)
{
draw_rle_sprite(footer_bmp, player_small_sprite, small_x_pos, small_y_pos);
small_x_pos += x_inc;
}
}
//--------- END -- CLASS player -----------
//--------- START -- CLASS explosion --------
explosion::explosion() : base_image(NULL, -1)
{ // This cannot be used.
index_low = index_high = -1; // invalid speed.
speed = frame_cnt = 0;
};
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) : base_image(dt, dst, x-(((*game_sprites->images)[i_low]->w) >> 1), y-(((*game_sprites->images)[i_low]->h) >> 1), z, i_low, bg_f, d)
{
center_x = x;
center_y = y;
speed = frame_cnt = f_speed;
index_low = i_low;
index_high = i_high;
};
explosion::explosion(const explosion &other)
{
center_x = other.center_x;
center_y = other.center_y;
speed = other.speed;
frame_cnt = other.frame_cnt;
index_low = other.index_low;
index_high = other.index_high;
};
explosion::~explosion()
{
};
int explosion::action(void)
{
RLE_SPRITE *sprite;
int index = get_sprite_index();
if(index < 0)
return G_FALSE;
if(frame_cnt > 0)
{
frame_cnt--;
return G_TRUE;
};
frame_cnt = speed;
index++;
if(index > index_high)
{
set_sprite_index(-1);
return G_TRUE;
}
else set_sprite_index(index);
sprite = (*game_sprites->images)[index];
set_pos((center_x - ((sprite->w) >> 1)), (center_y - ((sprite->h) >> 1)), G_FALSE);
};
//--------- END -- CLASS explosion --------
//--------- START -- CLASS formation --------
formation::formation()
{
buffer = NULL;
items = NULL;
live_items = 0;
};
formation::formation(const st_formation_param &p)
{
int i;
int j;
st_item *p_item;
buffer = p.buffer;
frame_rate = frame_counter = p.frame_rate;
counter = 0;
items = p.list;
x_left_border = p.x_left_border;
x_right_border = p.x_right_border;
y_top_border = p.y_top_border;
y_bottom_border = p.y_bottom_border;
rows = p.rows;
cols = p.cols;
moves = p.moves;
current_move = 0;
move_count = moves[current_move].times;
live_items = 0;
for(j = 0; j < cols; j++)
for(i = 0; i < rows; i++)
{ // count live items.
p_item = &items[j]+(i * cols);
if(p_item->state != ITEM_IS_DEAD)
live_items++;
}
}
#define HANDLE_ITEM \
{ /* Using a MACRO to handle formation-movements */ \
p = &items[j]+(i * cols); \
if(p->state != ITEM_IS_DEAD) \
{ \
p->x += moves[current_move].x_inc; \
p->y += moves[current_move].y_inc; \
if(p->state == ITEM_IN_FORMATION) \
{ \
(p->sprite)->set_pos(p->x,p->y, G_FALSE); \
(p->sprite)->play_anim(); \
} \
} \
}
void formation::move_formation_right()
{ // Run on formation from right to left.
int i;
int j;
st_item *p;
for(j = cols-1; j >= 0; j--)
for(i = 0; i < rows; i++)
HANDLE_ITEM;
counter++; // Counting formation moves for sync.
}
void formation::move_formation_left()
{ // Run on formation from left to right.
int i;
int j;
st_item *p;
for(j = 0; j < cols; j++)
for(i = 0; i < rows; i++)
HANDLE_ITEM;
counter++; // Counting formation moves for sync.
}
void formation::move_formation_down()
{ // Run on formation from bottom to top.
int i;
int j;
st_item *p;
for(i = rows-1; i >=0; i--)
for(j = 0; j < cols; j++)
HANDLE_ITEM;
counter++; // Counting formation moves for sync.
}
void formation::move_formation_up()
{ // Run on formation from top to bottom.
int i;
int j;
st_item *p;
for(i = 0; i < rows; i++)
for(j = 0; j < cols; j++)
HANDLE_ITEM;
counter++; // Counting formation moves for sync.
}
int formation::test_formation_right()
{
int i;
int j;
st_item *p;
for(j = cols-1; j >= 0; j--)
for(i = 0; i < rows; i++)
{
p = &items[j]+(i * cols);
// allegro_message("row = <%d> col = <%d> state = <%d>",i, j, p->state);
if(p->state != ITEM_IS_DEAD)
if((p->x + (p->sprite->get_sprite())->w) >= x_right_border)
{
move_count = 0; // clear move count
return G_TRUE;
}
else
return G_FALSE;
}
return G_FALSE;
}
int formation::test_formation_left()
{
int i;
int j;
st_item *p;
for(j = 0; j < cols; j++)
for(i = 0; i < rows; i++)
{
p = &items[j]+(i * cols);
if(p->state != ITEM_IS_DEAD)
if(p->x <= x_left_border)
{
move_count = 0; // clear move count
return G_TRUE;
}
else
return G_FALSE;
}
return G_FALSE;
}
int formation::test_formation_bottom()
{
int i;
int j;
st_item *p;
for(i = rows-1; i >=0; i--)
for(j = 0; j < cols; j++)
{
p = &items[j]+(i * cols);
if(p->state != ITEM_IS_DEAD)
if((p->y + (p->sprite->get_sprite())->h) >= y_bottom_border)
{
move_count = 0; // clear move count
return G_TRUE;
}
else
return G_FALSE;
}
return G_FALSE;
}
int formation::test_formation_top()
{
int i;
int j;
st_item *p;
for(i = 0; i < rows; i++)
for(j = 0; j < cols; j++)
{
p = &items[j]+(i * cols);
if(p->state != ITEM_IS_DEAD)
if(p->y <= y_top_border)
{
move_count = 0; // clear move count
return G_TRUE;
}
else
return G_FALSE;
}
return G_FALSE;
}
void formation::remove(void)
{
int i, j;
st_item *p;
for(j = 0; j < cols; j++)
for(i = 0; i < rows; i++)
{
p = &items[j]+(i * cols);
if(p->state == ITEM_IN_FORMATION)
p->sprite->remove();
}
}
void formation::draw(void)
{
int i, j;
st_item *p;
for(j = 0; j < cols; j++)
for(i = 0; i < rows; i++)
{
p = &items[j]+(i * cols);
if(p->state == ITEM_IN_FORMATION)
p->sprite->draw();
}
}
int formation::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)
{
int i, j;
int s_index;
st_item *p;
for(j = 0; j < cols; j++)
for(i = rows-1; i >=0; i--)
{
p = &items[j]+(i * cols);
if(p->state != ITEM_IS_DEAD)
if(p->sprite->collision(x_pos, y_pos, *(*game_sprites->images)[bullet_index]))
{ // Kill this item
s_index = p->sprite->get_sprite_index();
int t_score = p->score;
if(p->state != ITEM_IN_FORMATION) // Double score in attack.
t_score <<= 1;
class explosion *e = new explosion(&(*game_sprites->images)[0], p->sprite->get_dest_bitmap(), e_index_low, e_index_high, p->sprite->get_x_pos()+(((*game_sprites->images)[s_index])->w >> 1), p->sprite->get_y_pos()+(((*game_sprites->images)[s_index])->h >> 1), EXPLOSION_Z_ORDER, 5, G_TRUE, G_FALSE);
if(e)
explosions_list.push_back(e);
if(t_score >= 200)
{ // Add bonus-score sprite to explosion list.
int t_bonus_index = (*game_sprites).gal_bonus_200;
if(t_score == 400)
t_bonus_index = (*game_sprites).gal_bonus_400;
if(t_score == 800)
t_bonus_index = (*game_sprites).gal_bonus_800;
e = new explosion(&(*game_sprites->images)[0], p->sprite->get_dest_bitmap(), t_bonus_index, t_bonus_index+2, p->sprite->get_x_pos()+(((*game_sprites->images)[s_index])->w >> 1), p->sprite->get_y_pos()+(((*game_sprites->images)[s_index])->h >> 1), EXPLOSION_Z_ORDER, 14, G_TRUE, G_FALSE);
if(e)
explosions_list.push_back(e);
}
if(do_sound) // Ganenrate explosion sound.
play_sample((SAMPLE *) s_data[p->sample].dat, 255, 128, 1000, 0);
delete (p->sprite);
p->sprite = NULL;
p->state = ITEM_IS_DEAD;
live_items--;
return (t_score);
}
}
return 0;
}
void formation::get_fire_options(st_pixel *opt, int max_col, int *n_opt)
{
int i, j;
st_item *p;
int lowest_fire_line = GAME_FOOTER_BORDER_LINE-60;
*n_opt = 0;
for(j = 0; j < cols; j++)
for(i = rows-1; i >=0; i--)
{
p = &items[j]+(i * cols);
if(p->state == ITEM_IN_FORMATION)
{
if(p->sprite->get_y_pos() > lowest_fire_line)
break; // Don't use this row for fire.
opt[*n_opt].x = p->sprite->get_x_pos() + ((*game_sprites->images)[p->sprite->get_sprite_index()]->w >> 1);
opt[*n_opt].y = p->sprite->get_y_pos() + (*game_sprites->images)[p->sprite->get_sprite_index()]->h;
(*n_opt)++;
if(*n_opt == max_col)
return;
else
break;
}
}
}
void formation::action()
{
if(!live_items)
return;
frame_counter--;
if(frame_counter)
return;
frame_counter = frame_rate;
// Finished moving the whole formation, test boundaries.
if(moves[current_move].x_inc > 0) // if we go to the right.
test_formation_right();
if(moves[current_move].x_inc < 0) // if we go to the left.
test_formation_left();
if(moves[current_move].y_inc > 0) // if we go to the down.
test_formation_bottom();
if(moves[current_move].y_inc < 0) // if we go to the up.
test_formation_top();
if(move_count == 0)
{
current_move += moves[current_move].int_to_next_move;
move_count = moves[current_move].times;
return;
}
if(moves[current_move].x_inc > 0)
move_formation_right();
if(moves[current_move].x_inc < 0)
move_formation_left();
if(moves[current_move].y_inc > 0)
move_formation_down();
if(moves[current_move].y_inc < 0)
move_formation_up();
move_count--;
}
formation::~formation()
{
for(int i = 0; i < rows*cols; i++)
if(items[i].sprite)
delete(items[i].sprite);
delete [] items;
delete [] moves;
};
//--------- END -- CLASS formation --------
|